pi-goal-list-loop-audit 0.28.34 → 0.29.1
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 +1 -0
- package/extensions/goal-loop-forever.ts +33 -0
- package/extensions/loops/goal.ts +158 -3
- package/extensions/reviewer.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -66,6 +66,7 @@ matches `/list show`.
|
|
|
66
66
|
/loop # draft the loop (agent grills; measure is test-run before you confirm)
|
|
67
67
|
/loop start "keep polishing the UI" # infinite metricless loop (v0.23.6): no plateau, no cap — ends at time=/tokens= or /loop stop
|
|
68
68
|
/loop respec # infinite metricless loop reconciling the codebase against the root SPEC.md / spec.md (v0.24.3) — 2 specs = you pick, 0 specs = drafting, 1 spec = auto-start (v0.24.4)
|
|
69
|
+
/loop audit # project-audit loop (v0.29.0): each iteration audits fresh, appends findings to .pi-glla/audit-loop/findings.md, fixes the top ones — the orchestrator counts open findings and the plateau stop ends it when the well is dry
|
|
69
70
|
/loop start "reduce TODOs" measure="grep -c TODO src.txt | head -1" direction=min
|
|
70
71
|
/loop start "shrink the bundle" measure="..." direction=min time=4 tokens=500000 # arbitrary bounds
|
|
71
72
|
/loop start "reduce TODOs" measure="..." direction=min branch=1 # scratch-branch mode
|
|
@@ -389,3 +389,36 @@ export function resolveSpecFile(cwd: string): string | null {
|
|
|
389
389
|
export function respecTarget(specName: string): string {
|
|
390
390
|
return `Reconcile the codebase against ${specName} (the project spec in the root). Read the spec critically first: if a requirement is stale, contradictory, or wrong for the current codebase, report the discrepancy and move on — never force the code to match a bad spec. Otherwise pick the next gap between spec and code and close it. Rotate: one iteration implements a missing or outdated spec item, the next audits something already "implemented" against the spec and fixes what drifted.`;
|
|
391
391
|
}
|
|
392
|
+
|
|
393
|
+
// ---- /loop audit (v0.29.0) ----
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* The audit loop's findings file — checkbox lines, append-only. The agent
|
|
397
|
+
* appends new findings and checks off fixed ones; the ORCHESTRATOR counts
|
|
398
|
+
* open boxes every iteration. The agent never self-reports progress.
|
|
399
|
+
*/
|
|
400
|
+
export const AUDIT_FINDINGS_REL = ".pi-glla/audit-loop/findings.md";
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* The audit-loop measure command: count open findings. Prints exactly one
|
|
404
|
+
* number in every file state (missing file / zero matches → 0). This is
|
|
405
|
+
* what respec (metricless) and the reviewer cascade (no termination) both
|
|
406
|
+
* lacked: an honest metric the plateau stop can believe — audits that stop
|
|
407
|
+
* surfacing new findings = the well is dry = the loop ends.
|
|
408
|
+
*/
|
|
409
|
+
export function auditMeasureCmd(): string {
|
|
410
|
+
return `c=$(grep -cE '^- \\[ \\]' ${AUDIT_FINDINGS_REL} 2>/dev/null); echo \${c:-0}`;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* The audit target. User's design (2026-07-29): "the looper running audits
|
|
415
|
+
* to see where to progress and what to fix" — the thing that fires at the
|
|
416
|
+
* end of goals and lists, finds the next batch of work, and works it.
|
|
417
|
+
* Each iteration: fresh audit pass → append NEW findings → fix the top
|
|
418
|
+
* open ones → check them off with the fix commit. Honesty laws: never
|
|
419
|
+
* fabricate findings, never rewrite the file's history, never check a box
|
|
420
|
+
* without the fix commit existing.
|
|
421
|
+
*/
|
|
422
|
+
export function auditTarget(): string {
|
|
423
|
+
return `Audit the project for real problems and fix them, iteration by iteration. Every iteration: (1) run a FRESH audit pass over the codebase — spawn Explore subagents for breadth — hunting real issues: bugs, broken flows, regressions, drift between docs and code, dead code, security holes. Not style nits, not speculative refactors. (2) Append every NEW finding as one checkbox line "- [ ] SEVERITY: short description (file:line)" to ${AUDIT_FINDINGS_REL} (create the file on the first finding; append-only — never delete, rewrite, or reorder existing lines; never re-report a finding already listed). (3) Fix the highest-severity OPEN finding(s) — real fixes, committed — then check the box: "- [x] … — fixed in <commit>". (4) Honesty law: never fabricate findings to look busy; never mark a finding fixed without the fix commit existing. When a full audit pass surfaces nothing new AND no open findings remain, say so plainly — the orchestrator counts open findings every iteration and the plateau stop ends the loop when the well is dry.`;
|
|
424
|
+
}
|
package/extensions/loops/goal.ts
CHANGED
|
@@ -114,6 +114,7 @@ import {
|
|
|
114
114
|
} from "../goal-settings.js";
|
|
115
115
|
import {
|
|
116
116
|
DEFAULT_REVIEWER_CONFIG,
|
|
117
|
+
normalizeObjective,
|
|
117
118
|
resolveReviewerConfig,
|
|
118
119
|
reviewerMenuOptions,
|
|
119
120
|
runReviewer,
|
|
@@ -161,6 +162,8 @@ import {
|
|
|
161
162
|
LOOP_DEFAULTS,
|
|
162
163
|
resolveSpecFiles,
|
|
163
164
|
respecTarget,
|
|
165
|
+
auditMeasureCmd,
|
|
166
|
+
auditTarget,
|
|
164
167
|
HELD_ON_RESTORE,
|
|
165
168
|
type LoopState,
|
|
166
169
|
} from "../goal-loop-forever.js";
|
|
@@ -544,6 +547,21 @@ function escalateSendRearmStorm(ctx: ExtensionContext, kind: "continuation" | "l
|
|
|
544
547
|
notifyExternal(ctx, "Loop stopped: send-retry storm.");
|
|
545
548
|
return;
|
|
546
549
|
}
|
|
550
|
+
if (
|
|
551
|
+
state.goal &&
|
|
552
|
+
(state.goal.status === "auditing" || completionAuditInFlight || state.goal.pendingCompletion)
|
|
553
|
+
) {
|
|
554
|
+
// v0.29.1: NEVER storm-pause the completion lifecycle. An isolated
|
|
555
|
+
// auditor run takes minutes and the main session is EXPECTED to be
|
|
556
|
+
// silent while it works — 15m of wedged re-arms + that silence is the
|
|
557
|
+
// exact trigger shape, so completing a goal under a wedged queue used
|
|
558
|
+
// to guarantee a mid-audit pause (field-observed in pully + hellhunter
|
|
559
|
+
// + junk-runner: "complete ending in a pause retry storm"). The audit
|
|
560
|
+
// lifecycle owns its own pauses (quota etc.).
|
|
561
|
+
appendLedger(ctx.cwd, "send_rearm_escalated_suppressed", { reason: "audit-lifecycle" });
|
|
562
|
+
ctx.ui.notify("Send-retry storm during the completion audit — NOT pausing; the auditor's silence is expected. If pi is wedged, restart; the stored claim survives.", "info");
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
547
565
|
if (state.goal && state.goal.status === "active") {
|
|
548
566
|
updateGoal({
|
|
549
567
|
status: "paused",
|
|
@@ -604,6 +622,30 @@ function heartbeatTick(): void {
|
|
|
604
622
|
// worse, the stall escalation would PAUSE the goal — silently cancelling
|
|
605
623
|
// the interruptedAt → auto-resume-on-restart promise the footer shows.
|
|
606
624
|
if (extensionApiStale) return;
|
|
625
|
+
// v0.29.1: stranded-audit recovery. A goal left in "auditing" with NO
|
|
626
|
+
// in-flight audit means the auditor's result never landed (wedged queue
|
|
627
|
+
// ate the tool result; compaction/restart mid-audit). Field-observed in
|
|
628
|
+
// pully: 12h+ stuck "auditing" while the model had already confabulated
|
|
629
|
+
// the closure narrative. The audit silence is expected ONLY while
|
|
630
|
+
// completionAuditInFlight — its absence here means the run is orphaned.
|
|
631
|
+
// Recover: a stored claim re-runs the auditor directly; otherwise resume
|
|
632
|
+
// active so the agent re-calls complete_goal.
|
|
633
|
+
if (
|
|
634
|
+
state.goal?.status === "auditing" &&
|
|
635
|
+
!completionAuditInFlight &&
|
|
636
|
+
Date.now() - lastActivityAt >= 90_000
|
|
637
|
+
) {
|
|
638
|
+
appendLedger(ctx.cwd, "stranded_audit_recovered", { goalId: state.goal.id, via: state.goal.pendingCompletion ? "stored-claim" : "resume-active" });
|
|
639
|
+
if (state.goal.pendingCompletion) {
|
|
640
|
+
ctx.ui.notify("Recovering a completion audit whose result never landed — re-running the auditor with the stored claim.", "info");
|
|
641
|
+
void retryStoredCompletionAudit(ctx, "quota-retry");
|
|
642
|
+
} else {
|
|
643
|
+
updateGoal({ status: "active" }, ctx);
|
|
644
|
+
ctx.ui.notify("A completion audit was interrupted (its result never landed). Resuming — re-call complete_goal when the deliverable still stands.", "warning");
|
|
645
|
+
scheduleContinuation(ctx, true);
|
|
646
|
+
}
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
607
649
|
// v0.26.5: pending-latch watchdog — a queued continuation whose turn
|
|
608
650
|
// trigger was dropped (field-observed post-compaction: continuation
|
|
609
651
|
// ACCEPTED at compact+0s, then 22 minutes of silence). The stuck latch
|
|
@@ -968,7 +1010,7 @@ function archiveCurrentGoal(ctx: ExtensionContext, status: Status, stopReason?:
|
|
|
968
1010
|
try { fs.unlinkSync(goalMdPath(ctx.cwd, goal.id)); } catch {}
|
|
969
1011
|
}
|
|
970
1012
|
state = { ...state, goal: { ...goal, status, archivedPath: path.relative(ctx.cwd, target) || target, stopReason } };
|
|
971
|
-
appendLedger(ctx.cwd, "goal_archived", { goalId: goal.id, status, stopReason });
|
|
1013
|
+
appendLedger(ctx.cwd, "goal_archived", { goalId: goal.id, status, stopReason, objective: goal.objective.slice(0, 300) });
|
|
972
1014
|
persistState(ctx);
|
|
973
1015
|
// Loop 2: a list-sourced goal COMPLETED → auto-activate the next item.
|
|
974
1016
|
// Aborts are user actions (/list next, /goal cancel, list_activate) which
|
|
@@ -978,7 +1020,12 @@ function archiveCurrentGoal(ctx: ExtensionContext, status: Status, stopReason?:
|
|
|
978
1020
|
if (goal.policy === "list" && status === "complete") {
|
|
979
1021
|
const advanced = activateNextListItem(ctx);
|
|
980
1022
|
// v0.26.0: the queue just EMPTIED on a completion → list-complete.
|
|
981
|
-
if (!advanced)
|
|
1023
|
+
if (!advanced) {
|
|
1024
|
+
fireReviewer(ctx, { kind: "list", goalId: goal.id, objective: goal.objective, terminal: "goal-complete" });
|
|
1025
|
+
// v0.29.0: the well ran dry — point at the project-audit loop. A
|
|
1026
|
+
// suggestion, not an action: consent, never auto-start (v0.28.28).
|
|
1027
|
+
ctx.ui.notify("List complete. /loop audit to sweep the project for the next batch of work.", "info");
|
|
1028
|
+
}
|
|
982
1029
|
return;
|
|
983
1030
|
}
|
|
984
1031
|
// v0.26.0: a /goal (non-list) reached a terminal state → maybe fire.
|
|
@@ -1665,8 +1712,57 @@ async function cmdTweak(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
1665
1712
|
* contract extraction) → appended to the queue → persisted → first item
|
|
1666
1713
|
* activated when nothing is running. Returns the count enqueued.
|
|
1667
1714
|
*/
|
|
1715
|
+
// v0.29.1: zombie-twin guard. A draft/enqueue whose objective matches a
|
|
1716
|
+
// goal COMPLETED in the last 24h re-creates just-finished work — field-
|
|
1717
|
+
// observed in junk-runner: the INFRA-NEW-18 close was re-drafted 3 minutes
|
|
1718
|
+
// after the auditor approved it and autoaccept waved the twin straight in,
|
|
1719
|
+
// where it stormed for 9h against a dead provider. Normalized compare (goal
|
|
1720
|
+
// ids stripped), 24h lookback, loud skip — never silent.
|
|
1721
|
+
const DUPLICATE_LOOKBACK_MS = 24 * 60 * 60 * 1000;
|
|
1722
|
+
const LEDGER_TAIL_BYTES = 256 * 1024;
|
|
1723
|
+
function recentlyCompletedObjectives(cwd: string): Set<string> {
|
|
1724
|
+
const done = new Set<string>();
|
|
1725
|
+
try {
|
|
1726
|
+
const p = ledgerPath(cwd);
|
|
1727
|
+
const size = fs.statSync(p).size;
|
|
1728
|
+
const buf = Buffer.alloc(Math.min(size, LEDGER_TAIL_BYTES));
|
|
1729
|
+
const fd = fs.openSync(p, "r");
|
|
1730
|
+
fs.readSync(fd, buf, 0, buf.length, Math.max(0, size - buf.length));
|
|
1731
|
+
fs.closeSync(fd);
|
|
1732
|
+
const cutoff = Date.now() - DUPLICATE_LOOKBACK_MS;
|
|
1733
|
+
for (const line of buf.toString("utf-8").split("\n")) {
|
|
1734
|
+
if (!line.includes('"goal_archived"') || !line.includes('"complete"')) continue;
|
|
1735
|
+
try {
|
|
1736
|
+
const e = JSON.parse(line);
|
|
1737
|
+
if (e?.type !== "goal_archived" || e.value?.status !== "complete") continue;
|
|
1738
|
+
if (!(Date.parse(e.ts ?? "") >= cutoff)) continue;
|
|
1739
|
+
// v0.29.1+ entries carry the objective inline; older entries fall
|
|
1740
|
+
// back to the archived goal file (## Objective → "> …" line).
|
|
1741
|
+
let objective = typeof e.value?.objective === "string" ? e.value.objective : "";
|
|
1742
|
+
if (!objective && e.value?.goalId) {
|
|
1743
|
+
try {
|
|
1744
|
+
const md = fs.readFileSync(archivedGoalPath(cwd, e.value.goalId), "utf-8");
|
|
1745
|
+
objective = md.split("## Objective")[1]?.split("\n").find((l: string) => l.startsWith("> "))?.slice(2) ?? "";
|
|
1746
|
+
} catch { /* archived file gone — skip */ }
|
|
1747
|
+
}
|
|
1748
|
+
if (objective) done.add(normalizeObjective(objective));
|
|
1749
|
+
} catch { /* malformed line — skip */ }
|
|
1750
|
+
}
|
|
1751
|
+
} catch { /* no ledger yet */ }
|
|
1752
|
+
return done;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1668
1755
|
function enqueueItems(ctx: ExtensionContext, texts: string[], source: string, opts?: { autoActivate?: boolean }): number {
|
|
1669
|
-
const
|
|
1756
|
+
const recentlyDone = recentlyCompletedObjectives(ctx.cwd);
|
|
1757
|
+
const fresh = texts.filter((t) => !recentlyDone.has(normalizeObjective(extractVerificationContract(t).objective)));
|
|
1758
|
+
const skipped = texts.length - fresh.length;
|
|
1759
|
+
if (skipped > 0) {
|
|
1760
|
+
const first = texts.find((t) => recentlyDone.has(normalizeObjective(extractVerificationContract(t).objective))) ?? "";
|
|
1761
|
+
appendLedger(ctx.cwd, "list_duplicate_skipped", { source, count: skipped, objective: first.slice(0, 200) });
|
|
1762
|
+
ctx.ui.notify(`Skipped ${skipped} item(s) duplicating work COMPLETED in the last 24h (zombie-twin guard): ${first.slice(0, 90)}`, "warning");
|
|
1763
|
+
}
|
|
1764
|
+
if (fresh.length === 0) return 0;
|
|
1765
|
+
const items = fresh.map((text) => {
|
|
1670
1766
|
const extracted = extractVerificationContract(text);
|
|
1671
1767
|
return { id: newGoalId(), objective: extracted.objective, verificationContract: extracted.verificationContract || undefined, addedAt: nowIso() };
|
|
1672
1768
|
});
|
|
@@ -2510,6 +2606,34 @@ async function cmdLoop(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
2510
2606
|
return;
|
|
2511
2607
|
}
|
|
2512
2608
|
|
|
2609
|
+
if (sub === "audit") {
|
|
2610
|
+
// v0.29.0: the project-audit loop (user design: "the looper running
|
|
2611
|
+
// audits to see where to progress and what to fix — the thing that
|
|
2612
|
+
// fires at the end of goals and lists"). Unlike respec this is a
|
|
2613
|
+
// METRIC loop: the orchestrator counts open findings every iteration,
|
|
2614
|
+
// direction=min, and the plateau stop is the termination — audits that
|
|
2615
|
+
// stop surfacing new findings = the well is dry. User typed the
|
|
2616
|
+
// command = the act (same auto-start rule as respec).
|
|
2617
|
+
if (state.goal && state.goal.status === "active") {
|
|
2618
|
+
ctx.ui.notify("A goal is active — /goal cancel or /goal pause it before starting a loop.", "warning");
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
2621
|
+
if (isLoopActive()) {
|
|
2622
|
+
ctx.ui.notify("A loop is already active. /loop stop first.", "warning");
|
|
2623
|
+
return;
|
|
2624
|
+
}
|
|
2625
|
+
await startLoopFromConfig(ctx, {
|
|
2626
|
+
target: auditTarget(),
|
|
2627
|
+
measureCmd: auditMeasureCmd(),
|
|
2628
|
+
direction: "min",
|
|
2629
|
+
plateauWindow: LOOP_DEFAULTS.plateauWindow,
|
|
2630
|
+
maxIterations: 0,
|
|
2631
|
+
branch: false,
|
|
2632
|
+
force: false,
|
|
2633
|
+
});
|
|
2634
|
+
return;
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2513
2637
|
if (sub === "respec") {
|
|
2514
2638
|
// v0.24.3: reconcile the codebase against the root spec, forever.
|
|
2515
2639
|
// Same auto-start path as /loop start (the user typed the command —
|
|
@@ -3223,6 +3347,20 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
3223
3347
|
details: {},
|
|
3224
3348
|
};
|
|
3225
3349
|
}
|
|
3350
|
+
// v0.29.1: zombie-twin guard — a draft (auto-accepted OR confirmed)
|
|
3351
|
+
// whose objective duplicates a goal COMPLETED in the last 24h is
|
|
3352
|
+
// re-creating finished work. The Confirm dialog never said it was a
|
|
3353
|
+
// duplicate, so the gate belongs here. Junk-runner field case: the
|
|
3354
|
+
// just-approved INFRA-NEW-18 close re-drafted itself 3 minutes later.
|
|
3355
|
+
if (recentlyCompletedObjectives(liveCtx.cwd).has(normalizeObjective(p.objective.trim()))) {
|
|
3356
|
+
draftingTarget = null;
|
|
3357
|
+
appendLedger(liveCtx.cwd, "draft_duplicate_skipped", { kind: isListDraft ? "list" : "goal", objective: p.objective.trim().slice(0, 200) });
|
|
3358
|
+
liveCtx.ui.notify(`Draft REJECTED (zombie-twin guard): this objective matches a goal completed in the last 24h. Tell the user the work is already done.`, "warning");
|
|
3359
|
+
return {
|
|
3360
|
+
content: [{ type: "text", text: "This draft duplicates a goal that was COMPLETED within the last 24 hours (normalized objective match). Do NOT re-propose the same work. Report to the user that the objective is already done (see /glla audits or the archive) and ask what genuinely new work to take on instead." }],
|
|
3361
|
+
details: {},
|
|
3362
|
+
};
|
|
3363
|
+
}
|
|
3226
3364
|
const confirmedTarget = draftingTarget;
|
|
3227
3365
|
draftingTarget = null;
|
|
3228
3366
|
const full = p.objective.trim() + (normContract ? `\nDone when:\n${normContract}` : "");
|
|
@@ -4850,6 +4988,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
4850
4988
|
getArgumentCompletions: completions([
|
|
4851
4989
|
["start", "skip drafting: /loop start \"<target>\" measure=\"<cmd>\" direction=min|max [window=5] [max=50]"],
|
|
4852
4990
|
["respec", "infinite metricless loop reconciling the codebase against the root SPEC.md"],
|
|
4991
|
+
["audit", "project-audit loop: each iteration audits fresh, appends findings, fixes the top ones — plateau stops when the well is dry (v0.29.0)"],
|
|
4853
4992
|
["status", "show metric, iteration, best/last values, stall count"],
|
|
4854
4993
|
["stop", "end the loop (keeps the best state)"],
|
|
4855
4994
|
["cancel", "alias of /loop stop — end the loop"],
|
|
@@ -5308,6 +5447,22 @@ export default function (pi: ExtensionAPI): void {
|
|
|
5308
5447
|
// 60-second provider hiccup waiting on a manual /goal resume.
|
|
5309
5448
|
const detail = text.trim() ? ` (last: ${text.trim().replace(/\s+/g, " ").slice(0, 160)})` : "";
|
|
5310
5449
|
const reason = `5 consecutive errors${detail}`;
|
|
5450
|
+
// v0.29.1: brake-cycle CAP. The v0.28.25 ladder slows the thrash
|
|
5451
|
+
// (1m→16m) but never STOPS it — junk-runner/hellhunter/pully each
|
|
5452
|
+
// burned 4+ pause↔retry cycles against provider windows that last
|
|
5453
|
+
// hours. After 6 consecutive brakes: park, no more auto-retries.
|
|
5454
|
+
if (errorBrakeStreak >= 6) {
|
|
5455
|
+
updateGoal({
|
|
5456
|
+
status: "paused",
|
|
5457
|
+
pauseKind: "error",
|
|
5458
|
+
pauseReason: `${reason} — 6 error-brakes in a row; the provider has been erroring for an extended window`,
|
|
5459
|
+
pauseSuggestedAction: "Check the provider/account (quota, outage), then /goal resume. No more automatic retries.",
|
|
5460
|
+
}, ctx);
|
|
5461
|
+
ctx.ui.notify(`${goalNoun()} parked: ${reason} — 6 brakes in a row, no more auto-retries. Check the provider, then /goal resume.`, "warning");
|
|
5462
|
+
notifyExternal(ctx, `${goalNoun()} parked: provider erroring across 6 error-brake cycles.`);
|
|
5463
|
+
appendLedger(ctx.cwd, "error_brake_capped", { streak: errorBrakeStreak, reason });
|
|
5464
|
+
return;
|
|
5465
|
+
}
|
|
5311
5466
|
// v0.28.25: the cooldown escalates per CONSECUTIVE brake — a fleet-wide
|
|
5312
5467
|
// 403 window is not cleared by re-braking every 60 seconds.
|
|
5313
5468
|
const cooldownMs = 60_000 * 2 ** Math.min(errorBrakeStreak, 4);
|
package/extensions/reviewer.ts
CHANGED
|
@@ -40,7 +40,7 @@ export const DEFAULT_REVIEWER_CONFIG: ReviewerConfig = {
|
|
|
40
40
|
mode: "on",
|
|
41
41
|
fireOn: ["goal-complete", "list-complete"],
|
|
42
42
|
doNotFireOn: ["goal-aborted", "goal-paused"],
|
|
43
|
-
cascade: ["convert-findings-to-list", "queue-leftovers", "
|
|
43
|
+
cascade: ["convert-findings-to-list", "queue-leftovers", "notify-and-idle"],
|
|
44
44
|
auditCadence: "every-clean-completion",
|
|
45
45
|
auditScope: "regression-scan",
|
|
46
46
|
leverageMode: "fix-without-confirm",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.1",
|
|
4
4
|
"description": "Goal. Loop. Audit. Done. \u2014 a pi-coding-agent extension that supervises long-running work, with isolated auditor on each completion. Beat bamboozling by design: the auditor runs in a fresh session with no extensions, no skills, no editor \u2014 only the read tools needed to verify your goal.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "dracon",
|