harb/tools/push3-evolution/mutate-cli.ts
openhands 547e8beae8 fix: Push3 evolution: selection loop orchestrator (#546)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 20:56:19 +00:00

57 lines
1.6 KiB
TypeScript

/**
* mutate-cli.ts — CLI wrapper for Push3 mutation operators.
*
* Commands:
* mutate <push3file> <rate> Apply `rate` random mutations.
* crossover <push3file1> <push3file2> Single-point crossover of two programs.
*
* Outputs the resulting Push3 program text to stdout.
* Exits 1 on invalid input or mutation failure.
*/
import { readFileSync } from 'fs';
import { parse } from '../push3-transpiler/src/parser';
import { mutate, crossover, serialize } from './mutate';
function loadProgram(filePath: string) {
const src = readFileSync(filePath, 'utf8');
return parse(src);
}
const [, , cmd, ...args] = process.argv;
switch (cmd) {
case 'mutate': {
const [file, rateStr] = args;
if (!file || !rateStr) {
process.stderr.write('Usage: mutate-cli mutate <push3file> <rate>\n');
process.exit(1);
}
const rate = parseInt(rateStr, 10);
if (isNaN(rate) || rate < 0) {
process.stderr.write(`Invalid rate: ${rateStr}\n`);
process.exit(1);
}
const program = loadProgram(file);
const mutated = mutate(program, rate);
process.stdout.write(serialize(mutated) + '\n');
break;
}
case 'crossover': {
const [file1, file2] = args;
if (!file1 || !file2) {
process.stderr.write('Usage: mutate-cli crossover <push3file1> <push3file2>\n');
process.exit(1);
}
const a = loadProgram(file1);
const b = loadProgram(file2);
const crossed = crossover(a, b);
process.stdout.write(serialize(crossed) + '\n');
break;
}
default:
process.stderr.write(`Unknown command: ${cmd}\nCommands: mutate, crossover\n`);
process.exit(1);
}