claude-evolve 1.3.11 → 1.3.13

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 CHANGED
@@ -172,7 +172,11 @@ Evolution experiments can fail for various reasons. The system tracks these fail
172
172
  ### Required
173
173
  - Node.js >= 14.0.0
174
174
  - Python 3.x (for algorithm execution)
175
- - Unix-like environment (macOS, Linux)
175
+ - Automatically detected on all platforms
176
+ - Windows: Uses `python` if it's Python 3
177
+ - macOS/Linux: Prefers `python3`
178
+ - Can override in config.yaml: `python_cmd: "C:\\Python39\\python.exe"`
179
+ - Bash shell (Git Bash on Windows, native on macOS/Linux)
176
180
  - [Claude CLI](https://docs.anthropic.com/en/docs/claude-code) (`claude` command)
177
181
 
178
182
  ### Optional (but recommended)
@@ -92,35 +92,69 @@ top_score=""
92
92
  top_id=""
93
93
  top_desc=""
94
94
 
95
- while IFS=, read -r id _ desc perf status; do
96
- [[ $id == "id" ]] && continue # Skip header
97
-
98
- ((total++))
99
-
100
- case "$status" in
101
- "complete" | "completed")
102
- ((completed++))
103
- # Only count performance for completed runs with non-zero values
104
- if [[ -n $perf && $perf != "" ]]; then
105
- # Skip zeros (they're errors)
106
- if (( $(echo "$perf > 0" | bc -l 2>/dev/null || echo "0") )); then
107
- total_performance=$(echo "$total_performance + $perf" | bc -l 2>/dev/null || echo "$total_performance")
108
- ((count_with_performance++))
109
-
110
- # Check if this is the top performer
111
- if [[ -z $top_score ]] || (($(echo "$perf > $top_score" | bc -l 2>/dev/null || echo "0"))); then
112
- top_score="$perf"
113
- top_id="$id"
114
- top_desc="$desc"
115
- fi
116
- fi
117
- fi
118
- ;;
119
- "running") ((running++)) ;;
120
- "failed" | "timeout" | "interrupted") ((failed++)) ;;
121
- *) ((pending++)) ;;
122
- esac
123
- done <"$csv_file"
95
+ # Use Python to parse CSV and generate stats
96
+ eval "$("$PYTHON_CMD" -c "
97
+ import csv
98
+
99
+ # Initialize counters
100
+ total = 0
101
+ completed = 0
102
+ running = 0
103
+ failed = 0
104
+ pending = 0
105
+ total_performance = 0
106
+ count_with_performance = 0
107
+ top_score = None
108
+ top_id = ''
109
+ top_desc = ''
110
+
111
+ with open('$csv_file', 'r') as f:
112
+ reader = csv.reader(f)
113
+ next(reader) # Skip header
114
+
115
+ for row in reader:
116
+ if len(row) < 5:
117
+ continue
118
+
119
+ id, _, desc, perf, status = row[:5]
120
+ total += 1
121
+
122
+ if status in ['complete', 'completed']:
123
+ completed += 1
124
+ if perf and perf != '':
125
+ try:
126
+ perf_val = float(perf)
127
+ if perf_val > 0: # Skip zeros (they're errors)
128
+ total_performance += perf_val
129
+ count_with_performance += 1
130
+
131
+ if top_score is None or perf_val > top_score:
132
+ top_score = perf_val
133
+ top_id = id
134
+ top_desc = desc
135
+ except ValueError:
136
+ pass
137
+ elif status == 'running':
138
+ running += 1
139
+ elif status in ['failed', 'timeout', 'interrupted']:
140
+ failed += 1
141
+ else:
142
+ pending += 1
143
+
144
+ # Output shell variable assignments
145
+ print(f'total={total}')
146
+ print(f'completed={completed}')
147
+ print(f'running={running}')
148
+ print(f'failed={failed}')
149
+ print(f'pending={pending}')
150
+ print(f'total_performance={total_performance}')
151
+ print(f'count_with_performance={count_with_performance}')
152
+ print(f'top_score={top_score if top_score is not None else \"\"}')
153
+ print(f'top_id=\"{top_id}\"')
154
+ # Escape special characters in description
155
+ desc_escaped = top_desc.replace('\\\\', '\\\\\\\\').replace('\"', '\\\\\"').replace('\$', '\\\\\$').replace('\`', '\\\\\`')
156
+ print(f'top_desc=\"{desc_escaped}\"')
157
+ ")"
124
158
 
125
159
  # Display summary
126
160
  echo "Total Candidates: $total"
@@ -154,30 +188,44 @@ echo "=== Generation Analysis ==="
154
188
  gen_stats_file="/tmp/evolution_gen_stats_$$.tmp"
155
189
  >"$gen_stats_file"
156
190
 
157
- while IFS=, read -r id _ desc perf status; do
158
- [[ $id == "id" ]] && continue # Skip header
159
-
160
- # Extract generation from ID
161
- gen="gen01" # default for old numeric IDs
162
- if [[ $id =~ ^(gen[0-9]+)- ]]; then
163
- gen="${BASH_REMATCH[1]}"
164
- elif [[ $id =~ ^[0-9]+$ ]]; then
165
- gen="gen00" # Mark old numeric IDs as gen00
166
- fi
167
-
168
- # Write generation data to temp file
169
- echo -n "$gen " >> "$gen_stats_file"
170
- if [[ $status =~ ^(complete|completed)$ && -n $perf && $perf != "" ]]; then
171
- # Exclude zeros from statistics (they're errors)
172
- if (( $(echo "$perf > 0" | bc -l 2>/dev/null || echo "0") )); then
173
- echo "completed $perf" >> "$gen_stats_file"
174
- else
175
- echo "error" >> "$gen_stats_file"
176
- fi
177
- else
178
- echo "incomplete" >> "$gen_stats_file"
179
- fi
180
- done <"$csv_file"
191
+ # Use Python to write generation stats
192
+ "$PYTHON_CMD" -c "
193
+ import csv
194
+ import re
195
+
196
+ with open('$csv_file', 'r') as f:
197
+ reader = csv.reader(f)
198
+ next(reader) # Skip header
199
+
200
+ with open('$gen_stats_file', 'w') as out:
201
+ for row in reader:
202
+ if len(row) < 5:
203
+ continue
204
+
205
+ id, _, desc, perf, status = row[:5]
206
+
207
+ # Extract generation from ID
208
+ gen = 'gen01' # default for old numeric IDs
209
+ match = re.match(r'^(gen[0-9]+)-', id)
210
+ if match:
211
+ gen = match.group(1)
212
+ elif re.match(r'^[0-9]+$', id):
213
+ gen = 'gen00' # Mark old numeric IDs as gen00
214
+
215
+ # Write generation data
216
+ out.write(gen + ' ')
217
+ if status in ['complete', 'completed'] and perf and perf != '':
218
+ try:
219
+ perf_val = float(perf)
220
+ if perf_val > 0:
221
+ out.write(f'completed {perf}\\n')
222
+ else:
223
+ out.write('error\\n')
224
+ except ValueError:
225
+ out.write('error\\n')
226
+ else:
227
+ out.write('incomplete\\n')
228
+ "
181
229
 
182
230
  # Process generation stats
183
231
  for gen in $(cut -d' ' -f1 "$gen_stats_file" | sort -u || echo ""); do
@@ -206,14 +254,30 @@ rm -f "$gen_stats_file"
206
254
 
207
255
  # Count valid performance entries for chart (excluding zeros)
208
256
  valid_performance_count=0
209
- while IFS=, read -r id _ desc perf status; do
210
- [[ $id == "id" ]] && continue # Skip header
211
- if [[ $status =~ ^(complete|completed)$ && -n $perf && $perf != "" ]]; then
212
- if (( $(echo "$perf > 0" | bc -l 2>/dev/null || echo "0") )); then
213
- ((valid_performance_count++))
214
- fi
215
- fi
216
- done <"$csv_file"
257
+ # Count valid performance entries using Python
258
+ valid_performance_count=$("$PYTHON_CMD" -c "
259
+ import csv
260
+
261
+ count = 0
262
+ with open('$csv_file', 'r') as f:
263
+ reader = csv.reader(f)
264
+ next(reader) # Skip header
265
+
266
+ for row in reader:
267
+ if len(row) < 5:
268
+ continue
269
+ status = row[4]
270
+ perf = row[3]
271
+
272
+ if status in ['complete', 'completed'] and perf and perf != '':
273
+ try:
274
+ if float(perf) > 0:
275
+ count += 1
276
+ except ValueError:
277
+ pass
278
+
279
+ print(count)
280
+ ")
217
281
 
218
282
  # Simple chart generation using gnuplot if available
219
283
  if command -v gnuplot >/dev/null 2>&1 && [[ $valid_performance_count -gt 0 ]]; then
@@ -250,40 +314,75 @@ if command -v gnuplot >/dev/null 2>&1 && [[ $valid_performance_count -gt 0 ]]; t
250
314
  max_row=0
251
315
  max_id=""
252
316
 
253
- while IFS=, read -r id _ desc perf status; do
254
- [[ $id == "id" ]] && continue # Skip header
255
- ((row_num++))
317
+ # Use Python to generate chart data
318
+ "$PYTHON_CMD" -c "
319
+ import csv
320
+ import re
321
+
322
+ row_num = 0
323
+ max_perf = 0
324
+ max_row = 0
325
+ max_id = ''
326
+
327
+ with open('$csv_file', 'r') as f:
328
+ reader = csv.reader(f)
329
+ next(reader) # Skip header
256
330
 
257
- # Extract generation from ID
258
- gen="gen01" # default
259
- if [[ $id =~ ^(gen[0-9]+)- ]]; then
260
- gen="${BASH_REMATCH[1]}"
261
- fi
331
+ data_lines = []
332
+ gen_temp_lines = []
262
333
 
263
- # Only include completed algorithms with non-zero performance
264
- if [[ -n $perf && $perf != "" && $status =~ ^(complete|completed)$ ]]; then
265
- # Skip zero values (they're errors)
266
- if (( $(echo "$perf > 0" | bc -l) )); then
267
- # Assign generation number for coloring (1-based)
268
- gen_num=1
269
- if [[ $id =~ ^gen([0-9]+)- ]]; then
270
- gen_num=$((10#${BASH_REMATCH[1]}))
271
- fi
272
-
273
- echo "$row_num \"$id\" $perf $gen_num" >>"$data_file"
334
+ for row in reader:
335
+ if len(row) < 5:
336
+ continue
337
+
338
+ row_num += 1
339
+ id, _, desc, perf, status = row[:5]
274
340
 
275
- # Track for generation averages
276
- echo "$gen $perf" >>"$gen_data_temp"
341
+ # Extract generation from ID
342
+ gen = 'gen01' # default
343
+ match = re.match(r'^(gen[0-9]+)-', id)
344
+ if match:
345
+ gen = match.group(1)
277
346
 
278
- # Track the winner
279
- if (( $(echo "$perf > $max_perf" | bc -l) )); then
280
- max_perf=$perf
281
- max_row=$row_num
282
- max_id=$id
283
- fi
284
- fi
285
- fi
286
- done <"$csv_file"
347
+ # Only include completed algorithms with non-zero performance
348
+ if perf and perf != '' and status in ['complete', 'completed']:
349
+ try:
350
+ perf_val = float(perf)
351
+ if perf_val > 0:
352
+ # Assign generation number for coloring (1-based)
353
+ gen_num = 1
354
+ match = re.match(r'^gen([0-9]+)-', id)
355
+ if match:
356
+ gen_num = int(match.group(1))
357
+
358
+ data_lines.append(f'{row_num} \"{id}\" {perf} {gen_num}')
359
+ gen_temp_lines.append(f'{gen} {perf}')
360
+
361
+ # Track the winner
362
+ if perf_val > max_perf:
363
+ max_perf = perf_val
364
+ max_row = row_num
365
+ max_id = id
366
+ except ValueError:
367
+ pass
368
+
369
+ # Write data file
370
+ with open('$data_file', 'a') as f:
371
+ for line in data_lines:
372
+ f.write(line + '\\n')
373
+
374
+ # Write gen temp file
375
+ with open('$gen_data_temp', 'a') as f:
376
+ for line in gen_temp_lines:
377
+ f.write(line + '\\n')
378
+
379
+ # Output max values for shell
380
+ print(f'max_perf={max_perf}')
381
+ print(f'max_row={max_row}')
382
+ print(f'max_id=\"{max_id}\"')
383
+ " | while read -r line; do
384
+ eval "$line"
385
+ done
287
386
 
288
387
  # Create generation averages file and track max generation
289
388
  gen_index=1
@@ -63,7 +63,18 @@ count_pending() {
63
63
  return
64
64
  fi
65
65
 
66
- echo "$csv_content" | awk -F',' 'NR>1 && ($5 == "pending" || $5 == "") { count++ } END { print count+0 }'
66
+ # Use Python for proper CSV parsing with quoted fields
67
+ echo "$csv_content" | "$PYTHON_CMD" -c "
68
+ import csv
69
+ import sys
70
+ reader = csv.reader(sys.stdin)
71
+ next(reader) # Skip header
72
+ count = 0
73
+ for row in reader:
74
+ if len(row) >= 5 and (row[4] == 'pending' or row[4] == ''):
75
+ count += 1
76
+ print(count)
77
+ "
67
78
  }
68
79
 
69
80
  # Start a worker
@@ -198,20 +209,42 @@ trap 'echo "[DISPATCHER] Exiting with code $?" >&2' EXIT
198
209
  # Check for stuck "running" candidates from previous runs
199
210
  check_stuck_candidates() {
200
211
  if read_csv_with_lock csv_content; then
201
- local stuck_count=$(echo "$csv_content" | awk -F',' 'NR>1 && $5 == "running" { count++ } END { print count+0 }')
212
+ local stuck_count=$(echo "$csv_content" | "$PYTHON_CMD" -c "
213
+ import csv
214
+ import sys
215
+ reader = csv.reader(sys.stdin)
216
+ next(reader) # Skip header
217
+ count = 0
218
+ for row in reader:
219
+ if len(row) >= 5 and row[4] == 'running':
220
+ count += 1
221
+ print(count)
222
+ ")
202
223
  if [[ $stuck_count -gt 0 ]]; then
203
224
  echo "[DISPATCHER] Found $stuck_count candidates stuck in 'running' status"
204
225
  echo "[DISPATCHER] Resetting them to 'pending' for retry..."
205
226
 
206
227
  # Reset stuck candidates
207
228
  if acquire_csv_lock; then
208
- awk -F',' -v OFS=',' '
209
- NR==1 { print }
210
- NR>1 {
211
- if ($5 == "running") $5 = "pending"
212
- print
213
- }
214
- ' "$FULL_CSV_PATH" > "${FULL_CSV_PATH}.tmp" && mv -f "${FULL_CSV_PATH}.tmp" "$FULL_CSV_PATH"
229
+ "$PYTHON_CMD" -c "
230
+ import csv
231
+ import sys
232
+
233
+ # Read CSV
234
+ with open('$FULL_CSV_PATH', 'r') as f:
235
+ reader = csv.reader(f)
236
+ rows = list(reader)
237
+
238
+ # Reset running to pending
239
+ for i in range(1, len(rows)):
240
+ if len(rows[i]) >= 5 and rows[i][4] == 'running':
241
+ rows[i][4] = 'pending'
242
+
243
+ # Write back
244
+ with open('${FULL_CSV_PATH}.tmp', 'w', newline='') as f:
245
+ writer = csv.writer(f)
246
+ writer.writerows(rows)
247
+ " && mv -f "${FULL_CSV_PATH}.tmp" "$FULL_CSV_PATH"
215
248
  release_csv_lock
216
249
  fi
217
250
  fi
@@ -247,7 +280,17 @@ while true; do
247
280
  # Debug: Show CSV status if no pending
248
281
  if [[ $pending_count -eq 0 ]]; then
249
282
  total_rows=$(read_csv_with_lock csv_content && echo "$csv_content" | wc -l | xargs)
250
- complete_count=$(read_csv_with_lock csv_content && echo "$csv_content" | awk -F',' 'NR>1 && $5 == "complete" { count++ } END { print count+0 }')
283
+ complete_count=$(read_csv_with_lock csv_content && echo "$csv_content" | "$PYTHON_CMD" -c "
284
+ import csv
285
+ import sys
286
+ reader = csv.reader(sys.stdin)
287
+ next(reader) # Skip header
288
+ count = 0
289
+ for row in reader:
290
+ if len(row) >= 5 and row[4] == 'complete':
291
+ count += 1
292
+ print(count)
293
+ ")
251
294
  echo "[DISPATCHER] CSV has $((total_rows-1)) total candidates, $complete_count complete"
252
295
  fi
253
296
 
@@ -74,29 +74,39 @@ if ! read_csv_with_lock csv_content; then
74
74
  exit 1
75
75
  fi
76
76
 
77
- # Extract candidate data
78
- found=false
79
- while IFS=, read -r csv_id csv_based_on csv_desc csv_perf csv_stat; do
80
- if [[ $csv_id == "$candidate_id" ]]; then
81
- id="$csv_id"
82
- based_on_id="$csv_based_on"
83
- description="$csv_desc"
84
- performance="$csv_perf"
85
- status="$csv_stat"
86
- found=true
87
- break
88
- fi
89
- done <<< "$csv_content"
77
+ # Extract candidate data using Python
78
+ eval "$("$PYTHON_CMD" -c "
79
+ import csv
80
+ import sys
81
+ import io
82
+
83
+ csv_content = '''$csv_content'''
84
+ reader = csv.reader(io.StringIO(csv_content))
85
+ next(reader) # Skip header
86
+
87
+ found = False
88
+ for row in reader:
89
+ if len(row) >= 5 and row[0] == '$candidate_id':
90
+ # Escape special characters for shell
91
+ desc = row[2].replace('\\\\', '\\\\\\\\').replace('\"', '\\\\\"').replace('\$', '\\\\\$').replace('\`', '\\\\\`')
92
+ print(f'id=\"{row[0]}\"')
93
+ print(f'based_on_id=\"{row[1]}\"')
94
+ print(f'description=\"{desc}\"')
95
+ print(f'performance=\"{row[3]}\"')
96
+ print(f'status=\"{row[4]}\"')
97
+ print('found=true')
98
+ found = True
99
+ break
100
+
101
+ if not found:
102
+ print('found=false')
103
+ ")"
90
104
 
91
105
  if [[ $found == false ]]; then
92
106
  echo "[ERROR] Candidate ID not found: $candidate_id" >&2
93
107
  exit 1
94
108
  fi
95
109
 
96
- # Clean up description
97
- description=${description#\"}
98
- description=${description%\"}
99
-
100
110
  echo "[WORKER-$$] Description: $description"
101
111
  echo "[WORKER-$$] Based on ID: $based_on_id"
102
112
 
package/lib/config.sh CHANGED
@@ -9,7 +9,25 @@ DEFAULT_BRIEF_FILE="BRIEF.md"
9
9
  DEFAULT_EVOLUTION_CSV="evolution.csv"
10
10
  DEFAULT_OUTPUT_DIR=""
11
11
  DEFAULT_PARENT_SELECTION="best"
12
- DEFAULT_PYTHON_CMD="python3"
12
+ # Detect Python command based on platform
13
+ detect_python_cmd() {
14
+ # Try python3 first (macOS, Linux)
15
+ if command -v python3 >/dev/null 2>&1; then
16
+ echo "python3"
17
+ # Try python (Windows, some Linux)
18
+ elif command -v python >/dev/null 2>&1; then
19
+ # Verify it's Python 3
20
+ if python -c "import sys; sys.exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then
21
+ echo "python"
22
+ else
23
+ echo "python3" # Fallback
24
+ fi
25
+ else
26
+ echo "python3" # Default fallback
27
+ fi
28
+ }
29
+
30
+ DEFAULT_PYTHON_CMD="$(detect_python_cmd)"
13
31
 
14
32
  # Default ideation strategy values
15
33
  DEFAULT_TOTAL_IDEAS=15
@@ -195,7 +213,16 @@ validate_config() {
195
213
 
196
214
  if ! command -v "$PYTHON_CMD" >/dev/null 2>&1; then
197
215
  echo "[ERROR] Python command not found: $PYTHON_CMD" >&2
216
+ echo "[ERROR] Please install Python 3.x or set python_cmd in config.yaml" >&2
217
+ echo "[ERROR] Examples: python_cmd: \"python\" or python_cmd: \"C:\\Python39\\python.exe\"" >&2
198
218
  ((errors++))
219
+ else
220
+ # Verify Python version is 3.x
221
+ if ! "$PYTHON_CMD" -c "import sys; sys.exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then
222
+ echo "[ERROR] Python 3.x required, but $PYTHON_CMD appears to be Python 2" >&2
223
+ echo "[ERROR] Please set python_cmd in config.yaml to point to Python 3" >&2
224
+ ((errors++))
225
+ fi
199
226
  fi
200
227
 
201
228
  return $errors
package/lib/csv-lock.sh CHANGED
@@ -94,19 +94,19 @@ update_csv_row_with_lock() {
94
94
  local target_id="$1"
95
95
  local field="$2"
96
96
  local value="$3"
97
- local csv_file="${EVOLUTION_DIR:-evolution}/evolution.csv"
97
+ local csv_file="${FULL_CSV_PATH:-${EVOLUTION_DIR:-evolution}/evolution.csv}"
98
98
 
99
99
  if ! acquire_csv_lock; then
100
100
  return 1
101
101
  fi
102
102
 
103
- # Determine field position
103
+ # Determine field position (0-based for Python)
104
104
  local field_pos
105
105
  case "$field" in
106
- "status") field_pos=5 ;;
107
- "performance") field_pos=4 ;;
108
- "description") field_pos=3 ;;
109
- "basedOnId") field_pos=2 ;;
106
+ "status") field_pos=4 ;;
107
+ "performance") field_pos=3 ;;
108
+ "description") field_pos=2 ;;
109
+ "basedOnId") field_pos=1 ;;
110
110
  *)
111
111
  echo "ERROR: Unknown field: $field" >&2
112
112
  release_csv_lock
@@ -114,11 +114,27 @@ update_csv_row_with_lock() {
114
114
  ;;
115
115
  esac
116
116
 
117
- # Update CSV using awk
118
- awk -F',' -v OFS=',' -v id="$target_id" -v pos="$field_pos" -v val="$value" '
119
- NR==1 || $1 != id { print }
120
- $1 == id { $pos = val; print }
121
- ' "$csv_file" > "${csv_file}.tmp" && mv -f "${csv_file}.tmp" "$csv_file"
117
+ # Update CSV using Python
118
+ "$PYTHON_CMD" -c "
119
+ import csv
120
+ import sys
121
+
122
+ # Read CSV
123
+ with open('$csv_file', 'r') as f:
124
+ reader = csv.reader(f)
125
+ rows = list(reader)
126
+
127
+ # Update the specific field
128
+ for i in range(1, len(rows)):
129
+ if rows[i][0] == '$target_id':
130
+ rows[i][$field_pos] = '$value'
131
+ break
132
+
133
+ # Write back
134
+ with open('${csv_file}.tmp', 'w', newline='') as f:
135
+ writer = csv.writer(f)
136
+ writer.writerows(rows)
137
+ " && mv -f "${csv_file}.tmp" "$csv_file"
122
138
 
123
139
  release_csv_lock
124
140
  return 0
@@ -127,27 +143,40 @@ update_csv_row_with_lock() {
127
143
  # Find next pending candidate with lock
128
144
  # Usage: next_pending=$(find_next_pending_with_lock)
129
145
  find_next_pending_with_lock() {
130
- local csv_file="${EVOLUTION_DIR:-evolution}/evolution.csv"
146
+ local csv_file="${FULL_CSV_PATH:-${EVOLUTION_DIR:-evolution}/evolution.csv}"
131
147
 
132
148
  if ! acquire_csv_lock; then
133
149
  return 1
134
150
  fi
135
151
 
136
- # Find oldest pending candidate and update to running
137
- local candidate=$(awk -F',' '
138
- NR>1 && ($5 == "pending" || $5 == "") { print $1; exit }
139
- ' "$csv_file")
152
+ # Find oldest pending candidate and update to running using Python
153
+ local candidate=$("$PYTHON_CMD" -c "
154
+ import csv
155
+ import sys
156
+
157
+ # Read CSV
158
+ with open('$csv_file', 'r') as f:
159
+ reader = csv.reader(f)
160
+ rows = list(reader)
161
+
162
+ # Find first pending candidate
163
+ candidate_id = None
164
+ for i in range(1, len(rows)):
165
+ if len(rows[i]) >= 5 and (rows[i][4] == 'pending' or rows[i][4] == ''):
166
+ candidate_id = rows[i][0]
167
+ rows[i][4] = 'running' # Update status
168
+ break
169
+
170
+ # Write back if we found a candidate
171
+ if candidate_id:
172
+ with open('${csv_file}.tmp', 'w', newline='') as f:
173
+ writer = csv.writer(f)
174
+ writer.writerows(rows)
175
+ print(candidate_id)
176
+ ")
140
177
 
141
178
  if [ -n "$candidate" ]; then
142
- # Update status to running while we have the lock
143
- awk -F',' -v OFS=',' -v id="$candidate" '
144
- NR==1 || $1 != id { print }
145
- $1 == id {
146
- # Preserve existing fields but set status to running
147
- if ($5 == "" || $5 == "pending") $5 = "running"
148
- print
149
- }
150
- ' "$csv_file" > "${csv_file}.tmp" && mv -f "${csv_file}.tmp" "$csv_file"
179
+ mv -f "${csv_file}.tmp" "$csv_file"
151
180
  fi
152
181
 
153
182
  release_csv_lock
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-evolve",
3
- "version": "1.3.11",
3
+ "version": "1.3.13",
4
4
  "bin": {
5
5
  "claude-evolve": "./bin/claude-evolve",
6
6
  "claude-evolve-main": "./bin/claude-evolve-main",