pi-goal-list-loop-audit 0.34.13 → 0.34.14
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/extensions/loops/goal.ts +40 -6
- package/package.json +1 -1
package/extensions/loops/goal.ts
CHANGED
|
@@ -411,6 +411,30 @@ function attemptAutoRecovery(ctx: ExtensionContext, where: string): boolean {
|
|
|
411
411
|
return true;
|
|
412
412
|
}
|
|
413
413
|
|
|
414
|
+
/** v0.34.14: /reload rebind detector. The extension runs INSIDE pi, so
|
|
415
|
+
* process.pid IS pi's pid: an instance that boots and finds its OWN pid
|
|
416
|
+
* already in the owner file is a /reload rebuild of a live session, not a
|
|
417
|
+
* cold boot. Rebinds always resume active goals/loops — holding mid-work
|
|
418
|
+
* after an in-place rebuild is pure friction (user directive: keep going
|
|
419
|
+
* unless we must stop; "the list is not continuing" after /reload,
|
|
420
|
+
* hellhunter 2026-08-01). Cold boots (new pid) still honor autoresume=off.
|
|
421
|
+
* Sidecar, not the ledger: read-before-write must be atomic-ish and the
|
|
422
|
+
* ledger is append-only. */
|
|
423
|
+
const SESSION_OWNER_FILE = "session-owner.json";
|
|
424
|
+
function claimSessionOwnerAndDetectRebind(cwd: string): boolean {
|
|
425
|
+
try {
|
|
426
|
+
const p = path.join(piGlaDir(cwd), SESSION_OWNER_FILE);
|
|
427
|
+
let prevPid: number | null = null;
|
|
428
|
+
try {
|
|
429
|
+
prevPid = (JSON.parse(fs.readFileSync(p, "utf-8")) as { pid?: number }).pid ?? null;
|
|
430
|
+
} catch { /* absent or corrupt — first boot */ }
|
|
431
|
+
fs.writeFileSync(p, JSON.stringify({ pid: process.pid, at: new Date().toISOString() }));
|
|
432
|
+
return prevPid !== null && prevPid === process.pid;
|
|
433
|
+
} catch {
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
414
438
|
/** v0.34.13: consume the sidecar marker on session restore. Single-use,
|
|
415
439
|
* freshness-bounded — a stale marker from an abandoned recovery must not
|
|
416
440
|
* surprise-resume a later session. */
|
|
@@ -680,7 +704,7 @@ const ZOMBIE_RUN_ALERT_THROTTLE_MS = 10 * 60_000;
|
|
|
680
704
|
// (sendMessage never threw; session reported idle) but started NO turn —
|
|
681
705
|
// transcript frozen, tokens flat, 10+ minutes of refires into the void.
|
|
682
706
|
// Same family as the post-compaction dropped trigger (v0.26.5), but the
|
|
683
|
-
// pending
|
|
707
|
+
// the pending latch needs idle&&pending and pi reported no pending
|
|
684
708
|
// here, and the zombie watchdog needs busy — this shape falls between both
|
|
685
709
|
// chairs. Disarm signal = real activity (agent_end/tool_call) AFTER the
|
|
686
710
|
// last send; a landed turn — even a lazy text-only one — disarms it.
|
|
@@ -3679,7 +3703,13 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
3679
3703
|
// logged as disapprovals.
|
|
3680
3704
|
const auditorRan = result.output.trim().length > 0;
|
|
3681
3705
|
// v0.28.5 (E2): a REAL auditor run clears the infra-error streak.
|
|
3682
|
-
|
|
3706
|
+
// v0.34.14: …but only a CLEAN one. A STALLED run returns the partial
|
|
3707
|
+
// output it streamed before the abort — non-empty, so auditorRan is
|
|
3708
|
+
// true — while result.error still marks it an infrastructure failure.
|
|
3709
|
+
// Clearing the streak on those meant the 3-strike breaker at :3874
|
|
3710
|
+
// NEVER engaged: pully 2026-08-01 looped 10-min stall cycles for 4h
|
|
3711
|
+
// (the auditor hung on an ssh/sudo verification every attempt).
|
|
3712
|
+
if (auditorRan && !result.error && (state.goal.auditInfraStreak ?? 0) > 0) updateGoal({ auditInfraStreak: undefined }, ctx);
|
|
3683
3713
|
const history = state.goal.auditHistory ?? [];
|
|
3684
3714
|
if (auditorRan) {
|
|
3685
3715
|
// v0.25.4: strip think-block leakage (MiniMax-M3 `</think>`
|
|
@@ -3878,11 +3908,11 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
3878
3908
|
auditHistory: history,
|
|
3879
3909
|
auditInfraStreak: infraStreak,
|
|
3880
3910
|
pauseKind: "error",
|
|
3881
|
-
pauseReason: `auditor infrastructure failed ${infraStreak}× in a row — the auditor model is likely broken (last: ${result.error.slice(0, 120)})`,
|
|
3911
|
+
pauseReason: `auditor infrastructure failed ${infraStreak}× in a row — the auditor model is likely broken OR a verification command is hanging (ssh/sudo/long test runs stall the stream) (last: ${result.error.slice(0, 120)})`,
|
|
3882
3912
|
pauseSuggestedAction: "Fix the auditor model (/glla model=provider/id) or restart pi, then /goal resume. Your work was NOT judged.",
|
|
3883
3913
|
}, ctx);
|
|
3884
3914
|
appendLedger(ctx.cwd, "goal_paused", { reason: `auditor infra streak ${infraStreak}: ${result.error.slice(0, 120)}` });
|
|
3885
|
-
ctx.ui.notify(`${goalNoun()} paused: auditor infrastructure failed ${infraStreak}× in a row
|
|
3915
|
+
ctx.ui.notify(`${goalNoun()} paused: auditor infrastructure failed ${infraStreak}× in a row — model broken or a verification command hanging (ssh/sudo/long runs). Fix with /glla model=... or unblock the command, then /goal resume.`, "warning");
|
|
3886
3916
|
notifyExternal(ctx, `${goalNoun()} paused: auditor infrastructure ${infraStreak}× — model likely broken.`);
|
|
3887
3917
|
return {
|
|
3888
3918
|
content: [{
|
|
@@ -6418,9 +6448,13 @@ export default function (pi: ExtensionAPI): void {
|
|
|
6418
6448
|
// v0.34.13: an auto-recovery /reload carries its own resume consent —
|
|
6419
6449
|
// the sidecar marker overrides autoresume=off for THIS restore only.
|
|
6420
6450
|
const recoveryResume = consumeRecoveryResume(ctx.cwd);
|
|
6451
|
+
// v0.34.14: a /reload rebind (same pi pid) ALWAYS resumes — the session
|
|
6452
|
+
// is live mid-work; holding is the "list is not continuing" bug.
|
|
6453
|
+
const rebindResume = claimSessionOwnerAndDetectRebind(ctx.cwd);
|
|
6454
|
+
if (rebindResume) appendLedger(ctx.cwd, "rebind_resume", { pid: process.pid });
|
|
6421
6455
|
if (isLoopActive()) {
|
|
6422
6456
|
const l = state.loop!;
|
|
6423
|
-
if (autoResume || recoveryResume) {
|
|
6457
|
+
if (autoResume || recoveryResume || rebindResume) {
|
|
6424
6458
|
ctx.ui.notify(
|
|
6425
6459
|
`Resuming loop (iteration ${l.iteration}/${l.maxIterations > 0 ? l.maxIterations : "∞"}, best ${l.bestValue ?? "n/a"}, stall ${l.stallCount}/${l.plateauWindow}): ${l.target.slice(0, 60)}`,
|
|
6426
6460
|
"info",
|
|
@@ -6441,7 +6475,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
6441
6475
|
// "load it but not auto start it"). Interrupted goals hold like
|
|
6442
6476
|
// everything else; autoresume=on (unattended rigs) still auto-resumes
|
|
6443
6477
|
// them, and the marker is cleared only on that promised auto-resume.
|
|
6444
|
-
if (autoResume || recoveryResume) {
|
|
6478
|
+
if (autoResume || recoveryResume || rebindResume) {
|
|
6445
6479
|
// v0.28.1 (S2): clear the stale-handle interrupt marker — this IS
|
|
6446
6480
|
// the auto-resume the marker promised.
|
|
6447
6481
|
if (wasInterrupted) updateGoal({ interruptedAt: undefined, interruptedReason: undefined }, ctx);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.34.
|
|
3
|
+
"version": "0.34.14",
|
|
4
4
|
"description": "Mission control for autonomous pi: interview-drafted goals, an audited task queue, and forever-loops (metric, spec, project-audit) that run for hours. An isolated extension-less auditor re-verifies every completion with raw evidence; confirmed drafts, decision pauses and consent gates keep you in charge.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "dracon",
|