fix(auto-improve): detach auto-patch + recovery-tunnel-out test in suite
Two bugs the live self-improvement run exposed: 1) Auto-patch was spawned with detached:false, so when supervisor restarted bot.js (file change after Pi's commit landed on the auto branch), the auto-patch child was killed mid-way — Pi's commit lived in the auto branch but never got cherry-picked. Recovered manually this round via reflog + cherry-pick. Now detached:true + child.unref() + a per-run log at state/_auto-patch-last.log so the operator can read Pi's full output later. 2) Pi's recovery-tunnel-out.test.js was created but not in npm test script; tests would have stayed unrun forever. Added. Also commits the Pi-authored skill (eb29591 cherry-picked): - runtime/skills/recovery-tunnel-out.js (+ test) - improvements to runtime/actions.js + runtime/skills/explore-far.js - wired into runtime/skills/index.js npm test 137/137. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+21
-16
@@ -51,31 +51,36 @@ function listPendingProposals() {
|
||||
}
|
||||
|
||||
function spawnPatcher(filename) {
|
||||
info("auto-improve", `spawning auto-patch for ${filename}`);
|
||||
info("auto-improve", `spawning auto-patch for ${filename} (detached)`);
|
||||
inFlight = true;
|
||||
// detached:true so the auto-patch child survives a supervisor restart
|
||||
// (which fires every time auto-patch's own commit lands and supervisor
|
||||
// notices runtime/*.js changed). Without this, Pi can write a perfect
|
||||
// commit on an auto/* branch but auto-patch gets killed BEFORE the
|
||||
// cherry-pick step. Observed live 2026-05-26: lost an
|
||||
// eb29591-quality fix that way; recovered manually via git
|
||||
// reflog + cherry-pick. We also pipe stdout/stderr to a log file
|
||||
// per-run so the operator can see Pi's full output later.
|
||||
const logPath = path.join(REPO_ROOT, "state", "_auto-patch-last.log");
|
||||
let logFd;
|
||||
try { logFd = fs.openSync(logPath, "w"); } catch { logFd = "ignore"; }
|
||||
const child = spawn(process.execPath, [PATCH_SCRIPT, filename], {
|
||||
cwd: REPO_ROOT,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
stdio: ["ignore", logFd, logFd],
|
||||
env: { ...process.env },
|
||||
detached: false,
|
||||
});
|
||||
let stdoutBuf = "";
|
||||
let stderrBuf = "";
|
||||
child.stdout.on("data", (c) => {
|
||||
stdoutBuf += c.toString();
|
||||
});
|
||||
child.stderr.on("data", (c) => {
|
||||
stderrBuf += c.toString();
|
||||
detached: true,
|
||||
});
|
||||
child.unref(); // critical: parent (bot.js) can exit without waiting
|
||||
child.on("exit", (code) => {
|
||||
inFlight = false;
|
||||
lastFinishedAt = Date.now();
|
||||
recentRuns.push(lastFinishedAt);
|
||||
const tail = (stdoutBuf + "\n" + stderrBuf).trim().split("\n").slice(-3).join(" | ");
|
||||
if (code === 0) info("auto-improve", `patch applied for ${filename}: ${tail}`);
|
||||
else warn("auto-improve", `patch did not apply (code=${code}) for ${filename}: ${tail}`);
|
||||
// We do NOT trigger supervisor restart manually — the supervisor's
|
||||
// fs.watch on runtime/*.js fires the moment the cherry-pick lands.
|
||||
if (code === 0) info("auto-improve", `patch applied for ${filename} (see ${logPath} for full output)`);
|
||||
else warn("auto-improve", `patch did not apply (code=${code}) for ${filename} (see ${logPath})`);
|
||||
});
|
||||
child.on("error", (e) => {
|
||||
warn("auto-improve", `spawn error: ${e.message}`);
|
||||
inFlight = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user