claude-evolve 1.3.38 → 1.3.40
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/README.md +46 -5
- package/bin/claude-evolve-analyze +34 -5
- package/bin/claude-evolve-cleanup +297 -0
- package/bin/claude-evolve-edit +293 -0
- package/bin/claude-evolve-ideate +6 -6
- package/bin/claude-evolve-main +35 -15
- package/bin/{claude-evolve-run-unified → claude-evolve-run} +143 -8
- package/bin/claude-evolve-status +220 -0
- package/bin/claude-evolve-worker +73 -11
- package/lib/config.sh +5 -3
- package/lib/csv-lock.sh +26 -4
- package/lib/csv_helper.py +1 -1
- package/package.json +1 -2
- package/templates/config.yaml +8 -7
- package/bin/claude-evolve-run-parallel.OLD +0 -389
- package/bin/claude-evolve-run.OLD +0 -662
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
# Load configuration
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
# shellcheck source=../lib/config.sh
|
|
8
|
+
source "$SCRIPT_DIR/../lib/config.sh"
|
|
9
|
+
|
|
10
|
+
# Use CLAUDE_EVOLVE_CONFIG if set, otherwise default
|
|
11
|
+
if [[ -n ${CLAUDE_EVOLVE_CONFIG:-} ]]; then
|
|
12
|
+
load_config "$CLAUDE_EVOLVE_CONFIG"
|
|
13
|
+
else
|
|
14
|
+
load_config
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Validate configuration
|
|
18
|
+
if ! validate_config; then
|
|
19
|
+
echo "[ERROR] Configuration validation failed" >&2
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# Function to show help
|
|
24
|
+
show_help() {
|
|
25
|
+
cat <<EOF
|
|
26
|
+
claude-evolve status - Show evolution progress and current leader
|
|
27
|
+
|
|
28
|
+
USAGE:
|
|
29
|
+
claude-evolve status [OPTIONS]
|
|
30
|
+
|
|
31
|
+
OPTIONS:
|
|
32
|
+
--brief Show only summary stats (no per-generation breakdown)
|
|
33
|
+
--winner Show only the current best performer
|
|
34
|
+
--help Show this help message
|
|
35
|
+
|
|
36
|
+
DESCRIPTION:
|
|
37
|
+
Displays evolution progress by generation including:
|
|
38
|
+
- Candidate counts by status (pending, complete, failed, running)
|
|
39
|
+
- Current best performer across all generations
|
|
40
|
+
- Generation-by-generation breakdown
|
|
41
|
+
|
|
42
|
+
EXAMPLES:
|
|
43
|
+
claude-evolve status # Full status report
|
|
44
|
+
claude-evolve status --brief # Just totals and winner
|
|
45
|
+
claude-evolve status --winner # Just the best performer
|
|
46
|
+
EOF
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# Parse arguments
|
|
50
|
+
SHOW_BRIEF=false
|
|
51
|
+
SHOW_WINNER_ONLY=false
|
|
52
|
+
|
|
53
|
+
while [[ $# -gt 0 ]]; do
|
|
54
|
+
case $1 in
|
|
55
|
+
--brief)
|
|
56
|
+
SHOW_BRIEF=true
|
|
57
|
+
shift
|
|
58
|
+
;;
|
|
59
|
+
--winner)
|
|
60
|
+
SHOW_WINNER_ONLY=true
|
|
61
|
+
shift
|
|
62
|
+
;;
|
|
63
|
+
--help)
|
|
64
|
+
show_help
|
|
65
|
+
exit 0
|
|
66
|
+
;;
|
|
67
|
+
*)
|
|
68
|
+
echo "[ERROR] Unknown option: $1" >&2
|
|
69
|
+
exit 1
|
|
70
|
+
;;
|
|
71
|
+
esac
|
|
72
|
+
done
|
|
73
|
+
|
|
74
|
+
# Check if CSV exists
|
|
75
|
+
if [[ ! -f "$FULL_CSV_PATH" ]]; then
|
|
76
|
+
echo "[ERROR] Evolution CSV not found: $FULL_CSV_PATH" >&2
|
|
77
|
+
echo "Run 'claude-evolve setup' first or navigate to the correct directory" >&2
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Determine what we're evolving based on paths
|
|
82
|
+
EVOLUTION_CONTEXT=""
|
|
83
|
+
if [[ -n "$EVOLUTION_DIR" ]]; then
|
|
84
|
+
# Get the evolution directory name (e.g., "evolution-atr" -> "ATR")
|
|
85
|
+
EVOLUTION_NAME=$(basename "$EVOLUTION_DIR")
|
|
86
|
+
EVOLUTION_CONTEXT="${EVOLUTION_NAME#evolution-}"
|
|
87
|
+
EVOLUTION_CONTEXT=$(echo "$EVOLUTION_CONTEXT" | tr '[:lower:]' '[:upper:]')
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# If we can't determine from evolution dir, try from algorithm path
|
|
91
|
+
if [[ -z "$EVOLUTION_CONTEXT" && -n "$ALGORITHM_PATH" ]]; then
|
|
92
|
+
# Get parent directory name or algorithm file name
|
|
93
|
+
if [[ -f "$FULL_ALGORITHM_PATH" ]]; then
|
|
94
|
+
ALGO_NAME=$(basename "$FULL_ALGORITHM_PATH" .py)
|
|
95
|
+
EVOLUTION_CONTEXT="$ALGO_NAME"
|
|
96
|
+
fi
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# Default if we still can't determine
|
|
100
|
+
if [[ -z "$EVOLUTION_CONTEXT" ]]; then
|
|
101
|
+
EVOLUTION_CONTEXT="Algorithm"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Main status reporting using Python
|
|
105
|
+
"$PYTHON_CMD" -c "
|
|
106
|
+
import csv
|
|
107
|
+
import sys
|
|
108
|
+
|
|
109
|
+
csv_file = '$FULL_CSV_PATH'
|
|
110
|
+
show_brief = '$SHOW_BRIEF' == 'true'
|
|
111
|
+
show_winner_only = '$SHOW_WINNER_ONLY' == 'true'
|
|
112
|
+
evolution_context = '$EVOLUTION_CONTEXT'
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
with open(csv_file, 'r') as f:
|
|
116
|
+
reader = csv.reader(f)
|
|
117
|
+
rows = list(reader)
|
|
118
|
+
|
|
119
|
+
if len(rows) <= 1:
|
|
120
|
+
print('No evolution candidates found')
|
|
121
|
+
sys.exit(0)
|
|
122
|
+
|
|
123
|
+
header = rows[0]
|
|
124
|
+
|
|
125
|
+
# Collect all candidates with scores and statuses
|
|
126
|
+
all_candidates = []
|
|
127
|
+
stats_by_gen = {}
|
|
128
|
+
total_stats = {'pending': 0, 'complete': 0, 'failed': 0, 'running': 0}
|
|
129
|
+
|
|
130
|
+
for row in rows[1:]:
|
|
131
|
+
if len(row) >= 1 and row[0]: # Must have an ID
|
|
132
|
+
candidate_id = row[0]
|
|
133
|
+
|
|
134
|
+
# Extract generation (e.g., 'gen03' from 'gen03-001')
|
|
135
|
+
if '-' in candidate_id:
|
|
136
|
+
gen = candidate_id.split('-')[0]
|
|
137
|
+
|
|
138
|
+
# Get status and performance
|
|
139
|
+
status = row[4] if len(row) > 4 and row[4] else 'pending'
|
|
140
|
+
performance = row[3] if len(row) > 3 and row[3] else ''
|
|
141
|
+
|
|
142
|
+
# Track by generation
|
|
143
|
+
if gen not in stats_by_gen:
|
|
144
|
+
stats_by_gen[gen] = {'pending': 0, 'complete': 0, 'failed': 0, 'running': 0}
|
|
145
|
+
|
|
146
|
+
if status in stats_by_gen[gen]:
|
|
147
|
+
stats_by_gen[gen][status] += 1
|
|
148
|
+
total_stats[status] += 1
|
|
149
|
+
else:
|
|
150
|
+
stats_by_gen[gen]['pending'] += 1
|
|
151
|
+
total_stats['pending'] += 1
|
|
152
|
+
|
|
153
|
+
# Collect for winner analysis (only completed with valid scores)
|
|
154
|
+
if status == 'complete' and performance:
|
|
155
|
+
try:
|
|
156
|
+
score = float(performance)
|
|
157
|
+
description = row[2] if len(row) > 2 else 'No description'
|
|
158
|
+
all_candidates.append((candidate_id, description, score))
|
|
159
|
+
except ValueError:
|
|
160
|
+
pass
|
|
161
|
+
|
|
162
|
+
# Find the winner
|
|
163
|
+
winner = None
|
|
164
|
+
if all_candidates:
|
|
165
|
+
winner = max(all_candidates, key=lambda x: x[2])
|
|
166
|
+
|
|
167
|
+
# Show winner only
|
|
168
|
+
if show_winner_only:
|
|
169
|
+
if winner:
|
|
170
|
+
print(f'🏆 CURRENT LEADER: {winner[0]} (score: {winner[2]:.4f})')
|
|
171
|
+
print(f' {winner[1]}')
|
|
172
|
+
else:
|
|
173
|
+
print('No completed candidates found')
|
|
174
|
+
sys.exit(0)
|
|
175
|
+
|
|
176
|
+
# Show header
|
|
177
|
+
print(f'🧬 Evolution Status Report - {evolution_context}')
|
|
178
|
+
print('=' * 50)
|
|
179
|
+
|
|
180
|
+
# Show overall stats
|
|
181
|
+
total_candidates = sum(total_stats.values())
|
|
182
|
+
if total_candidates > 0:
|
|
183
|
+
print(f'📊 OVERALL: {total_candidates} total candidates')
|
|
184
|
+
print(f' • {total_stats[\"pending\"]} pending')
|
|
185
|
+
print(f' • {total_stats[\"complete\"]} complete')
|
|
186
|
+
print(f' • {total_stats[\"failed\"]} failed')
|
|
187
|
+
print(f' • {total_stats[\"running\"]} running')
|
|
188
|
+
print()
|
|
189
|
+
|
|
190
|
+
# Show current winner
|
|
191
|
+
if winner:
|
|
192
|
+
print(f'🏆 CURRENT LEADER: {winner[0]} (score: {winner[2]:.4f})')
|
|
193
|
+
print(f' {winner[1]}')
|
|
194
|
+
print()
|
|
195
|
+
else:
|
|
196
|
+
print('🏆 CURRENT LEADER: None (no completed candidates)')
|
|
197
|
+
print()
|
|
198
|
+
|
|
199
|
+
# Show per-generation breakdown (unless brief mode)
|
|
200
|
+
if not show_brief and stats_by_gen:
|
|
201
|
+
print('📈 BY GENERATION:')
|
|
202
|
+
for gen in sorted(stats_by_gen.keys()):
|
|
203
|
+
data = stats_by_gen[gen]
|
|
204
|
+
total = sum(data.values())
|
|
205
|
+
|
|
206
|
+
# Find best performer in this generation
|
|
207
|
+
gen_candidates = [c for c in all_candidates if c[0].startswith(gen + '-')]
|
|
208
|
+
gen_best = max(gen_candidates, key=lambda x: x[2]) if gen_candidates else None
|
|
209
|
+
|
|
210
|
+
status_str = f'{data[\"pending\"]}p {data[\"complete\"]}c {data[\"failed\"]}f {data[\"running\"]}r'
|
|
211
|
+
|
|
212
|
+
if gen_best:
|
|
213
|
+
print(f' {gen}: {total} total ({status_str}) - best: {gen_best[0]} ({gen_best[2]:.4f})')
|
|
214
|
+
else:
|
|
215
|
+
print(f' {gen}: {total} total ({status_str}) - best: none')
|
|
216
|
+
|
|
217
|
+
except Exception as e:
|
|
218
|
+
print(f'Error reading evolution status: {e}')
|
|
219
|
+
sys.exit(1)
|
|
220
|
+
"
|
package/bin/claude-evolve-worker
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
set -e
|
|
6
6
|
|
|
7
|
+
# Track temp file for cleanup
|
|
8
|
+
temp_file=""
|
|
9
|
+
|
|
10
|
+
# Cleanup function for temp files
|
|
11
|
+
cleanup_temp() {
|
|
12
|
+
if [[ -n "$temp_file" && -f "$temp_file" ]]; then
|
|
13
|
+
rm -f "$temp_file"
|
|
14
|
+
echo "[WORKER-$$] Cleaned up temp file: $temp_file" >&2
|
|
15
|
+
fi
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# Set trap to clean up temp files on exit
|
|
19
|
+
trap cleanup_temp EXIT INT TERM
|
|
20
|
+
|
|
7
21
|
# Load configuration
|
|
8
22
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
23
|
# shellcheck source=../lib/config.sh
|
|
@@ -47,7 +61,7 @@ done
|
|
|
47
61
|
if [[ -z $candidate_id ]]; then
|
|
48
62
|
candidate_id=$(find_next_pending_with_lock)
|
|
49
63
|
if [[ -z $candidate_id ]]; then
|
|
50
|
-
echo "[
|
|
64
|
+
echo "[DEBUG] No pending candidates found" >&2
|
|
51
65
|
exit 0
|
|
52
66
|
fi
|
|
53
67
|
else
|
|
@@ -130,27 +144,35 @@ else
|
|
|
130
144
|
fi
|
|
131
145
|
fi
|
|
132
146
|
|
|
133
|
-
# Generate output file
|
|
147
|
+
# Generate output file path
|
|
134
148
|
if [[ $id =~ ^[0-9]+$ ]]; then
|
|
135
149
|
output_file="$FULL_OUTPUT_DIR/evolution_id${id}.py"
|
|
136
150
|
else
|
|
137
151
|
output_file="$FULL_OUTPUT_DIR/evolution_${id}.py"
|
|
138
152
|
fi
|
|
139
153
|
|
|
154
|
+
# Use temp file for mutations to avoid partial/failed edits
|
|
155
|
+
temp_file="${output_file}.tmp$$"
|
|
156
|
+
|
|
140
157
|
# Check if processing should be skipped using common logic
|
|
141
158
|
eval "$("$PYTHON_CMD" "$SCRIPT_DIR/../lib/evolution_processor.py" "$id" "$based_on_id" "$FULL_OUTPUT_DIR" "$ROOT_DIR" "$parent_file" "$output_file")"
|
|
142
159
|
|
|
143
|
-
# Handle copy operation
|
|
160
|
+
# Handle copy operation to temp file
|
|
144
161
|
if [[ "$skip_copy" == "True" ]]; then
|
|
145
162
|
echo "[WORKER-$$] ⚠️ Skipping copy - $reason"
|
|
146
163
|
else
|
|
147
|
-
cp "$parent_file" "$
|
|
148
|
-
echo "[WORKER-$$] Copied parent to: $
|
|
164
|
+
cp "$parent_file" "$temp_file"
|
|
165
|
+
echo "[WORKER-$$] Copied parent to temp file: $temp_file"
|
|
149
166
|
fi
|
|
150
167
|
|
|
151
168
|
# Handle Claude mutation based on skip flags
|
|
152
169
|
if [[ "$skip_claude" == "True" ]]; then
|
|
153
170
|
echo "[WORKER-$$] ⚠️ Skipping Claude processing - $reason"
|
|
171
|
+
# If we have a temp file but are skipping Claude, move it to final location
|
|
172
|
+
if [[ -f "$temp_file" ]]; then
|
|
173
|
+
mv "$temp_file" "$output_file"
|
|
174
|
+
echo "[WORKER-$$] Moved temp file to final location (no Claude processing)"
|
|
175
|
+
fi
|
|
154
176
|
else
|
|
155
177
|
# Check for claude CLI
|
|
156
178
|
claude_cmd="${CLAUDE_CMD:-claude}"
|
|
@@ -164,7 +186,7 @@ else
|
|
|
164
186
|
echo "[WORKER-$$] Using Claude $CLAUDE_MODEL for mutation"
|
|
165
187
|
|
|
166
188
|
# Create mutation prompt
|
|
167
|
-
prompt="Edit the file $
|
|
189
|
+
prompt="Edit the file $temp_file to implement this specific change: $description
|
|
168
190
|
|
|
169
191
|
Requirements:
|
|
170
192
|
- Edit the file directly (don't just provide comments or suggestions)
|
|
@@ -189,9 +211,14 @@ The file currently contains the parent algorithm. Modify it according to the des
|
|
|
189
211
|
claude_output=$(echo "$prompt" | "$claude_cmd" --dangerously-skip-permissions --model $CLAUDE_MODEL -p 2>&1 | tee -a "$LOGFILE")
|
|
190
212
|
claude_exit_code=${PIPESTATUS[1]}
|
|
191
213
|
|
|
192
|
-
# Check for rate limit
|
|
193
|
-
if echo "$claude_output" | grep -q "
|
|
214
|
+
# Check for rate limit (multiple possible messages)
|
|
215
|
+
if echo "$claude_output" | grep -q -E "(usage limit|rate limit|limit reached|too many requests)"; then
|
|
194
216
|
echo "[ERROR] Claude API rate limit reached" >&2
|
|
217
|
+
# Clean up the temp file
|
|
218
|
+
if [[ -f "$temp_file" ]]; then
|
|
219
|
+
rm "$temp_file"
|
|
220
|
+
echo "[WORKER-$$] Cleaned up temp file due to rate limit" >&2
|
|
221
|
+
fi
|
|
195
222
|
# Reset to pending so it can be retried later
|
|
196
223
|
update_csv_row_with_lock "$candidate_id" "status" "pending"
|
|
197
224
|
exit 2 # Special exit code for rate limit
|
|
@@ -199,9 +226,42 @@ The file currently contains the parent algorithm. Modify it according to the des
|
|
|
199
226
|
|
|
200
227
|
if [[ $claude_exit_code -ne 0 ]]; then
|
|
201
228
|
echo "[ERROR] Claude failed to mutate algorithm" >&2
|
|
229
|
+
# Clean up the temp file
|
|
230
|
+
if [[ -f "$temp_file" ]]; then
|
|
231
|
+
rm "$temp_file"
|
|
232
|
+
echo "[WORKER-$$] Cleaned up temp file due to Claude failure" >&2
|
|
233
|
+
fi
|
|
202
234
|
update_csv_row_with_lock "$candidate_id" "status" "failed"
|
|
203
235
|
exit 1
|
|
204
236
|
fi
|
|
237
|
+
|
|
238
|
+
# Verify that Claude actually modified the file
|
|
239
|
+
if [[ -f "$temp_file" && -f "$parent_file" ]]; then
|
|
240
|
+
if cmp -s "$temp_file" "$parent_file"; then
|
|
241
|
+
echo "" >&2
|
|
242
|
+
echo "🚨🚨🚨 RED ALERT: UNCHANGED ALGORITHM DETECTED 🚨🚨🚨" >&2
|
|
243
|
+
echo "ERROR: Temp file is IDENTICAL to parent algorithm!" >&2
|
|
244
|
+
echo "ERROR: Claude failed to make any changes" >&2
|
|
245
|
+
echo "ERROR: Marking as failed - no evaluation will run" >&2
|
|
246
|
+
echo "🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨" >&2
|
|
247
|
+
echo "" >&2
|
|
248
|
+
|
|
249
|
+
# Clean up temp file and mark as failed
|
|
250
|
+
rm "$temp_file"
|
|
251
|
+
update_csv_row_with_lock "$candidate_id" "status" "failed"
|
|
252
|
+
exit 1
|
|
253
|
+
else
|
|
254
|
+
# Changes were made - move temp file to final location
|
|
255
|
+
mv "$temp_file" "$output_file"
|
|
256
|
+
echo "[WORKER-$$] Changes detected - moved to: $output_file"
|
|
257
|
+
fi
|
|
258
|
+
else
|
|
259
|
+
# If we can't compare, assume it's okay and move the file
|
|
260
|
+
if [[ -f "$temp_file" ]]; then
|
|
261
|
+
mv "$temp_file" "$output_file"
|
|
262
|
+
echo "[WORKER-$$] Moved temp file to: $output_file"
|
|
263
|
+
fi
|
|
264
|
+
fi
|
|
205
265
|
fi
|
|
206
266
|
|
|
207
267
|
# Run evaluator
|
|
@@ -244,7 +304,7 @@ if [[ $eval_exit_code -eq 0 ]]; then
|
|
|
244
304
|
# First, check if output is just a plain number
|
|
245
305
|
if [[ $eval_output =~ ^[[:space:]]*-?[0-9]+\.?[0-9]*[[:space:]]*$ ]]; then
|
|
246
306
|
score=$(echo "$eval_output" | tr -d ' ')
|
|
247
|
-
if
|
|
307
|
+
if [[ $(echo "$score == 0" | bc -l) == "1" ]]; then
|
|
248
308
|
update_csv_row_with_lock "$candidate_id" "status" "failed"
|
|
249
309
|
update_csv_row_with_lock "$candidate_id" "performance" "$score"
|
|
250
310
|
echo "[WORKER-$$] ✗ Evaluation failed with score 0"
|
|
@@ -286,7 +346,7 @@ if [[ $eval_exit_code -eq 0 ]]; then
|
|
|
286
346
|
# Fallback: Try simple grep for score/performance fields
|
|
287
347
|
if score=$(echo "$eval_output" | grep -o '"score"[[:space:]]*:[[:space:]]*[0-9.]*' | cut -d: -f2 | tr -d ' '); then
|
|
288
348
|
if [[ -n $score ]]; then
|
|
289
|
-
if
|
|
349
|
+
if [[ $(echo "$score == 0" | bc -l) == "1" ]]; then
|
|
290
350
|
update_csv_row_with_lock "$candidate_id" "status" "failed"
|
|
291
351
|
update_csv_row_with_lock "$candidate_id" "performance" "$score"
|
|
292
352
|
echo "[WORKER-$$] ✗ Evaluation failed with score 0"
|
|
@@ -303,7 +363,7 @@ if [[ $eval_exit_code -eq 0 ]]; then
|
|
|
303
363
|
# Try "performance" field
|
|
304
364
|
if score=$(echo "$eval_output" | grep -o '"performance"[[:space:]]*:[[:space:]]*[0-9.]*' | cut -d: -f2 | tr -d ' '); then
|
|
305
365
|
if [[ -n $score ]]; then
|
|
306
|
-
if
|
|
366
|
+
if [[ $(echo "$score == 0" | bc -l) == "1" ]]; then
|
|
307
367
|
update_csv_row_with_lock "$candidate_id" "status" "failed"
|
|
308
368
|
update_csv_row_with_lock "$candidate_id" "performance" "$score"
|
|
309
369
|
echo "[WORKER-$$] ✗ Evaluation failed with score 0"
|
|
@@ -319,6 +379,8 @@ if [[ $eval_exit_code -eq 0 ]]; then
|
|
|
319
379
|
|
|
320
380
|
echo "[ERROR] No score found in evaluator output" >&2
|
|
321
381
|
echo "[ERROR] Expected: plain number (e.g., 1.23) or JSON with 'score' or 'performance' field" >&2
|
|
382
|
+
echo "[ERROR] Actual evaluator output was:" >&2
|
|
383
|
+
echo "$eval_output" >&2
|
|
322
384
|
update_csv_row_with_lock "$candidate_id" "status" "failed"
|
|
323
385
|
exit 1
|
|
324
386
|
else
|
package/lib/config.sh
CHANGED
|
@@ -78,7 +78,7 @@ load_config() {
|
|
|
78
78
|
|
|
79
79
|
# Load config if found
|
|
80
80
|
if [[ -f "$config_file" ]]; then
|
|
81
|
-
echo "[
|
|
81
|
+
echo "[DEBUG] Loading configuration from: $config_file" >&2
|
|
82
82
|
# Simple YAML parsing for key: value pairs and nested structures
|
|
83
83
|
local in_ideation_section=false
|
|
84
84
|
local in_parallel_section=false
|
|
@@ -143,7 +143,6 @@ load_config() {
|
|
|
143
143
|
else
|
|
144
144
|
# Handle top-level keys
|
|
145
145
|
case $key in
|
|
146
|
-
evolution_dir) EVOLUTION_DIR="$value" ;;
|
|
147
146
|
algorithm_file) ALGORITHM_FILE="$value" ;;
|
|
148
147
|
evaluator_file) EVALUATOR_FILE="$value" ;;
|
|
149
148
|
brief_file) BRIEF_FILE="$value" ;;
|
|
@@ -152,6 +151,9 @@ load_config() {
|
|
|
152
151
|
parent_selection) PARENT_SELECTION="$value" ;;
|
|
153
152
|
python_cmd) PYTHON_CMD="$value" ;;
|
|
154
153
|
auto_ideate) AUTO_IDEATE="$value" ;;
|
|
154
|
+
evolution_dir)
|
|
155
|
+
echo "[WARN] evolution_dir in config is ignored - automatically inferred from config file location" >&2
|
|
156
|
+
;;
|
|
155
157
|
esac
|
|
156
158
|
fi
|
|
157
159
|
done < "$config_file"
|
|
@@ -163,7 +165,7 @@ load_config() {
|
|
|
163
165
|
local config_dir=$(dirname "$config_file")
|
|
164
166
|
if [[ "$config_dir" != "." && "$config_dir" != "" ]]; then
|
|
165
167
|
EVOLUTION_DIR="$config_dir"
|
|
166
|
-
echo "[
|
|
168
|
+
echo "[DEBUG] Using evolution directory from config path: $EVOLUTION_DIR" >&2
|
|
167
169
|
fi
|
|
168
170
|
fi
|
|
169
171
|
|
package/lib/csv-lock.sh
CHANGED
|
@@ -110,7 +110,13 @@ release_csv_lock() {
|
|
|
110
110
|
# Usage: read_csv_with_lock <variable_name>
|
|
111
111
|
read_csv_with_lock() {
|
|
112
112
|
local var_name="$1"
|
|
113
|
-
|
|
113
|
+
|
|
114
|
+
# Ensure we have the full CSV path set
|
|
115
|
+
if [[ -z "$FULL_CSV_PATH" ]]; then
|
|
116
|
+
echo "[ERROR] FULL_CSV_PATH not set in read_csv_with_lock" >&2
|
|
117
|
+
return 1
|
|
118
|
+
fi
|
|
119
|
+
local csv_file="$FULL_CSV_PATH"
|
|
114
120
|
|
|
115
121
|
if ! acquire_csv_lock; then
|
|
116
122
|
return 1
|
|
@@ -130,7 +136,12 @@ read_csv_with_lock() {
|
|
|
130
136
|
# Write CSV with lock
|
|
131
137
|
# Usage: echo "content" | write_csv_with_lock
|
|
132
138
|
write_csv_with_lock() {
|
|
133
|
-
|
|
139
|
+
# Ensure we have the full CSV path set
|
|
140
|
+
if [[ -z "$FULL_CSV_PATH" ]]; then
|
|
141
|
+
echo "[ERROR] FULL_CSV_PATH not set in write_csv_with_lock" >&2
|
|
142
|
+
return 1
|
|
143
|
+
fi
|
|
144
|
+
local csv_file="$FULL_CSV_PATH"
|
|
134
145
|
local temp_file="${csv_file}.tmp.$$"
|
|
135
146
|
|
|
136
147
|
if ! acquire_csv_lock; then
|
|
@@ -153,7 +164,13 @@ update_csv_row_with_lock() {
|
|
|
153
164
|
local target_id="$1"
|
|
154
165
|
local field="$2"
|
|
155
166
|
local value="$3"
|
|
156
|
-
|
|
167
|
+
|
|
168
|
+
# Ensure we have the full CSV path set
|
|
169
|
+
if [[ -z "$FULL_CSV_PATH" ]]; then
|
|
170
|
+
echo "[ERROR] FULL_CSV_PATH not set in update_csv_row_with_lock" >&2
|
|
171
|
+
return 1
|
|
172
|
+
fi
|
|
173
|
+
local csv_file="$FULL_CSV_PATH"
|
|
157
174
|
|
|
158
175
|
if ! acquire_csv_lock; then
|
|
159
176
|
return 1
|
|
@@ -202,7 +219,12 @@ with open('${csv_file}.tmp', 'w', newline='') as f:
|
|
|
202
219
|
# Find next pending candidate with lock
|
|
203
220
|
# Usage: next_pending=$(find_next_pending_with_lock)
|
|
204
221
|
find_next_pending_with_lock() {
|
|
205
|
-
|
|
222
|
+
# Ensure we have the full CSV path set
|
|
223
|
+
if [[ -z "$FULL_CSV_PATH" ]]; then
|
|
224
|
+
echo "[ERROR] FULL_CSV_PATH not set in find_next_pending_with_lock" >&2
|
|
225
|
+
return 1
|
|
226
|
+
fi
|
|
227
|
+
local csv_file="$FULL_CSV_PATH"
|
|
206
228
|
|
|
207
229
|
if ! acquire_csv_lock; then
|
|
208
230
|
return 1
|
package/lib/csv_helper.py
CHANGED
|
@@ -91,7 +91,7 @@ def main():
|
|
|
91
91
|
performance = data.get('performance') or data.get('score', 0)
|
|
92
92
|
|
|
93
93
|
# Build fields to update
|
|
94
|
-
fields = {'performance': performance, 'status': 'complete' if performance
|
|
94
|
+
fields = {'performance': performance, 'status': 'complete' if performance != 0 else 'failed'}
|
|
95
95
|
|
|
96
96
|
# Add all other fields from the JSON
|
|
97
97
|
for key, value in data.items():
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-evolve",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.40",
|
|
4
4
|
"bin": {
|
|
5
5
|
"claude-evolve": "./bin/claude-evolve",
|
|
6
6
|
"claude-evolve-main": "./bin/claude-evolve-main",
|
|
7
7
|
"claude-evolve-setup": "./bin/claude-evolve-setup",
|
|
8
8
|
"claude-evolve-ideate": "./bin/claude-evolve-ideate",
|
|
9
9
|
"claude-evolve-run": "./bin/claude-evolve-run",
|
|
10
|
-
"claude-evolve-run-parallel": "./bin/claude-evolve-run-parallel",
|
|
11
10
|
"claude-evolve-worker": "./bin/claude-evolve-worker",
|
|
12
11
|
"claude-evolve-analyze": "./bin/claude-evolve-analyze",
|
|
13
12
|
"claude-evolve-config": "./bin/claude-evolve-config"
|
package/templates/config.yaml
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
# claude-evolve configuration file
|
|
2
2
|
# This file defines paths and settings for the evolution process
|
|
3
|
+
#
|
|
4
|
+
# NOTE: The evolution directory is automatically inferred from this config file's location.
|
|
5
|
+
# For example, if this file is at /path/to/my-experiment/config.yaml,
|
|
6
|
+
# then the evolution directory will be /path/to/my-experiment/
|
|
3
7
|
|
|
4
|
-
#
|
|
5
|
-
evolution_dir: "evolution"
|
|
6
|
-
|
|
7
|
-
# Algorithm and evaluator file paths (relative to evolution_dir)
|
|
8
|
+
# Algorithm and evaluator file paths (relative to evolution directory)
|
|
8
9
|
algorithm_file: "algorithm.py"
|
|
9
10
|
evaluator_file: "evaluator.py"
|
|
10
11
|
brief_file: "BRIEF.md"
|
|
11
12
|
|
|
12
|
-
# CSV file for tracking evolution (relative to
|
|
13
|
+
# CSV file for tracking evolution (relative to evolution directory)
|
|
13
14
|
evolution_csv: "evolution.csv"
|
|
14
15
|
|
|
15
|
-
# Output directory for generated algorithms (relative to
|
|
16
|
-
# Leave empty to use
|
|
16
|
+
# Output directory for generated algorithms (relative to evolution directory)
|
|
17
|
+
# Leave empty to use evolution directory directly
|
|
17
18
|
output_dir: ""
|
|
18
19
|
|
|
19
20
|
# Parent algorithm selection strategy
|