pi-goal-list-loop-audit 0.24.0 → 0.24.2
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 +2 -0
- package/extensions/goal-loop-auditor.ts +17 -9
- package/extensions/goal-loop-core.ts +16 -1
- package/extensions/goal-loop-shield.ts +18 -0
- package/extensions/loops/goal.ts +97 -3
- package/package.json +1 -1
- package/prompts/goal-loop-forever-metricless.md +2 -0
- package/prompts/goal-loop-forever.md +2 -0
package/README.md
CHANGED
|
@@ -57,6 +57,7 @@ matches `/list show`.
|
|
|
57
57
|
/list next # skip current, activate next
|
|
58
58
|
/list remove <n> # drop item n from the list
|
|
59
59
|
/list clear # empty the list
|
|
60
|
+
/list cancel # stop the whole list: abort the active item + drop all waiting
|
|
60
61
|
/loop # draft the loop (agent grills; measure is test-run before you confirm)
|
|
61
62
|
/loop start "keep polishing the UI" # infinite metricless loop (v0.23.6): no plateau, no cap — ends at time=/tokens= or /loop stop
|
|
62
63
|
/loop start "reduce TODOs" measure="grep -c TODO src.txt | head -1" direction=min
|
|
@@ -198,6 +199,7 @@ No external watchdog plugin needed.
|
|
|
198
199
|
/glla tokenlimit=0 # explicitly no cap (the default)
|
|
199
200
|
/glla wedgealert=30 # hung-command alert minutes (default: 30, 0 = off)
|
|
200
201
|
/glla autoresume=on # held goals/loops auto-resume in fresh sessions (unattended rigs)
|
|
202
|
+
/glla auditcap=5 # pause the goal after N consecutive auditor disapprovals (default 3, 0 = unlimited)
|
|
201
203
|
/glla autoaccept=on # drafts ACTIVATE without the Confirm dialog (unattended rigs)
|
|
202
204
|
/glla project tokenlimit=500 # rare per-project override
|
|
203
205
|
```
|
|
@@ -34,6 +34,9 @@ import { AUDITOR_STALL_MS } from "./goal-loop-backoff.js";
|
|
|
34
34
|
export interface GoalAuditorResult {
|
|
35
35
|
approved: boolean;
|
|
36
36
|
disapproved: boolean;
|
|
37
|
+
/** v0.24.2: third verdict — the goal can NEVER be satisfied as stated. */
|
|
38
|
+
impossible?: boolean;
|
|
39
|
+
impossibleReason?: string;
|
|
37
40
|
output: string;
|
|
38
41
|
model: string;
|
|
39
42
|
thinkingLevel?: ThinkingLevel;
|
|
@@ -107,6 +110,8 @@ function buildGoalAuditorPrompt(goal: Goal, completionSummary: string | null | u
|
|
|
107
110
|
"Return a concise audit report. The final line MUST be exactly one of:",
|
|
108
111
|
"<approved/>",
|
|
109
112
|
"<disapproved/>",
|
|
113
|
+
"<impossible>one-line reason</impossible>",
|
|
114
|
+
"Use <impossible> ONLY when the objective can NEVER be satisfied as stated — contradictory requirements, a premise that is factually wrong, or resources the agent can never obtain. Incomplete or shoddy work is <disapproved/>, not impossible.",
|
|
110
115
|
"",
|
|
111
116
|
"Goal markdown (full state):",
|
|
112
117
|
"<goal>",
|
|
@@ -149,7 +154,7 @@ function buildGoalAuditorPrompt(goal: Goal, completionSummary: string | null | u
|
|
|
149
154
|
? ["4. Verify that the executor has satisfied every item in the <verification_contract>. If any item is missing or weakly addressed, disapprove."]
|
|
150
155
|
: []),
|
|
151
156
|
"5. Explain missing or weak evidence, especially scaffold-vs-final quality gaps.",
|
|
152
|
-
"6. End with exactly <approved/> only if the objective is truly complete; otherwise end with exactly <disapproved/>.",
|
|
157
|
+
"6. End with exactly <approved/> only if the objective is truly complete; <impossible>reason</impossible> if it can never be satisfied as stated; otherwise end with exactly <disapproved/>.",
|
|
153
158
|
...(goal.verificationContract?.trim()
|
|
154
159
|
? [
|
|
155
160
|
"",
|
|
@@ -175,8 +180,8 @@ function buildGoalAuditorPrompt(goal: Goal, completionSummary: string | null | u
|
|
|
175
180
|
|
|
176
181
|
// regression_shield lives in goal-loop-shield.ts (dependency-free, so unit
|
|
177
182
|
// tests can import it without pulling in pi). Re-exported for callers.
|
|
178
|
-
export { checkRegressionShield, contractItems, type RegressionShieldResult } from "./goal-loop-shield.js";
|
|
179
|
-
import { checkRegressionShield } from "./goal-loop-shield.js";
|
|
183
|
+
export { checkRegressionShield, contractItems, parseAuditorVerdict, type RegressionShieldResult } from "./goal-loop-shield.js";
|
|
184
|
+
import { checkRegressionShield, parseAuditorVerdict } from "./goal-loop-shield.js";
|
|
180
185
|
|
|
181
186
|
// =================================================================
|
|
182
187
|
// Auditor entry point
|
|
@@ -354,18 +359,19 @@ export async function runGoalCompletionAuditor(args: {
|
|
|
354
359
|
};
|
|
355
360
|
}
|
|
356
361
|
|
|
357
|
-
const
|
|
358
|
-
const approved =
|
|
359
|
-
const disapproved =
|
|
362
|
+
const parsed = parseAuditorVerdict(outputParts.join("\n\n"));
|
|
363
|
+
const approved = parsed.approved;
|
|
364
|
+
const disapproved = parsed.disapproved;
|
|
365
|
+
const impossible = parsed.impossible;
|
|
360
366
|
|
|
361
|
-
if (!approved && !disapproved) {
|
|
367
|
+
if (!approved && !disapproved && !impossible) {
|
|
362
368
|
return {
|
|
363
369
|
approved: false,
|
|
364
370
|
disapproved: false,
|
|
365
371
|
output,
|
|
366
372
|
model: modelLabel(model),
|
|
367
373
|
thinkingLevel,
|
|
368
|
-
error: `Auditor produced no verdict marker (<approved/>/<disapproved
|
|
374
|
+
error: `Auditor produced no verdict marker (<approved/>/<disapproved/>/<impossible>)${streamError ? ` — stream error: ${streamError}` : ""}. Treating as an error, not a verdict.`,
|
|
369
375
|
};
|
|
370
376
|
}
|
|
371
377
|
|
|
@@ -407,6 +413,8 @@ export async function runGoalCompletionAuditor(args: {
|
|
|
407
413
|
return {
|
|
408
414
|
approved,
|
|
409
415
|
disapproved,
|
|
416
|
+
impossible,
|
|
417
|
+
impossibleReason: parsed.impossibleReason,
|
|
410
418
|
output,
|
|
411
419
|
model: modelLabel(model),
|
|
412
420
|
thinkingLevel,
|
|
@@ -416,7 +424,7 @@ export async function runGoalCompletionAuditor(args: {
|
|
|
416
424
|
|
|
417
425
|
progress.phase = "complete";
|
|
418
426
|
emitProgress();
|
|
419
|
-
return { approved, disapproved, output, model: modelLabel(model), thinkingLevel };
|
|
427
|
+
return { approved, disapproved, impossible, impossibleReason: parsed.impossibleReason, output, model: modelLabel(model), thinkingLevel };
|
|
420
428
|
} catch (err) {
|
|
421
429
|
// v0.11.1 (audit critical): a runtime exception is INFRASTRUCTURE, never
|
|
422
430
|
// a verdict. The three-way split identifies infra by `error &&
|
|
@@ -88,6 +88,9 @@ export interface AuditVerdict {
|
|
|
88
88
|
at: string;
|
|
89
89
|
approved: boolean;
|
|
90
90
|
disapproved: boolean;
|
|
91
|
+
/** v0.24.2: the auditor's third verdict — the goal can NEVER be satisfied as stated. */
|
|
92
|
+
impossible?: boolean;
|
|
93
|
+
impossibleReason?: string;
|
|
91
94
|
model: string;
|
|
92
95
|
thinkingLevel?: string;
|
|
93
96
|
report?: string;
|
|
@@ -368,6 +371,18 @@ export interface State {
|
|
|
368
371
|
loop?: import("./goal-loop-forever.js").LoopState;
|
|
369
372
|
}
|
|
370
373
|
|
|
374
|
+
/** v0.24.2: count TRAILING consecutive disapprovals (the disapproval-cap
|
|
375
|
+
* input). Shield-blocks (approved:true) and infra errors (neither flag)
|
|
376
|
+
* break the streak — they are not verdicts on the work. */
|
|
377
|
+
export function countTrailingDisapprovals(history: AuditVerdict[]): number {
|
|
378
|
+
let n = 0;
|
|
379
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
380
|
+
if (history[i]!.disapproved) n++;
|
|
381
|
+
else break;
|
|
382
|
+
}
|
|
383
|
+
return n;
|
|
384
|
+
}
|
|
385
|
+
|
|
371
386
|
/** Default per-goal token budget (v0.9.7): a runaway threshold, not a
|
|
372
387
|
* "big goal" threshold — real research/feature goals legitimately burn 2-4M.
|
|
373
388
|
* Loop 3 doesn't rely on this cap (it has max-iterations + plateau brakes). */
|
|
@@ -499,7 +514,7 @@ export function renderGoalMarkdown(goal: Goal): string {
|
|
|
499
514
|
lines.push("## Audit history");
|
|
500
515
|
lines.push("");
|
|
501
516
|
for (const v of goal.auditHistory) {
|
|
502
|
-
lines.push(`- ${v.at} — ${v.approved ? "approved" : "disapproved"} — \`${v.model}\``);
|
|
517
|
+
lines.push(`- ${v.at} — ${v.approved ? "approved" : v.impossible ? "impossible" : "disapproved"} — \`${v.model}\``);
|
|
503
518
|
}
|
|
504
519
|
lines.push("");
|
|
505
520
|
}
|
|
@@ -94,3 +94,21 @@ export function checkRegressionShield(report: string, contract: string): Regress
|
|
|
94
94
|
hasEvidenceBlock,
|
|
95
95
|
};
|
|
96
96
|
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* v0.24.2: pure auditor-verdict parser (approved / disapproved / impossible).
|
|
100
|
+
* Lives here (not goal-loop-auditor.ts) so tests can import it without
|
|
101
|
+
* dragging in the auditor's relative .js imports. The verdict is read from
|
|
102
|
+
* the last output block that mentions any verdict tag.
|
|
103
|
+
*/
|
|
104
|
+
export function parseAuditorVerdict(output: string): { approved: boolean; disapproved: boolean; impossible: boolean; impossibleReason?: string } {
|
|
105
|
+
const parts = output.split("\n\n");
|
|
106
|
+
const lastAssistant = [...parts].reverse().find((t) => /<\/?(approved|disapproved|impossible)[ />]/i.test(t)) ?? output;
|
|
107
|
+
const impossibleMatch = /<impossible>([\s\S]*?)<\/impossible>/i.exec(lastAssistant);
|
|
108
|
+
return {
|
|
109
|
+
approved: /<approved\/>/i.test(lastAssistant),
|
|
110
|
+
disapproved: /<disapproved\/>/i.test(lastAssistant),
|
|
111
|
+
impossible: impossibleMatch !== null,
|
|
112
|
+
impossibleReason: impossibleMatch?.[1]?.trim().slice(0, 300) || undefined,
|
|
113
|
+
};
|
|
114
|
+
}
|
package/extensions/loops/goal.ts
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
LIST_DRAFTING_BLOCK_MESSAGE,
|
|
41
41
|
sumNewAssistantTokens,
|
|
42
42
|
takeAt,
|
|
43
|
+
countTrailingDisapprovals,
|
|
43
44
|
goalArgsNeedDrafting,
|
|
44
45
|
buildSeedGrillMessage,
|
|
45
46
|
askUserQuestionAnswered,
|
|
@@ -849,7 +850,32 @@ async function cmdList(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
849
850
|
state = { ...state, list: [] };
|
|
850
851
|
persistState(ctx);
|
|
851
852
|
appendLedger(ctx.cwd, "list_cleared", {});
|
|
852
|
-
ctx.ui.notify("List cleared. Active goal (if any) is untouched — /goal cancel for that.", "info");
|
|
853
|
+
ctx.ui.notify("List cleared. Active goal (if any) is untouched — /goal cancel for that, /list cancel to stop the whole list.", "info");
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// v0.24.1: ONE verb for "stop this whole list" — aborts the active item
|
|
858
|
+
// when it's list-sourced AND drops the waiting items. Before this the user
|
|
859
|
+
// had to know to combine /goal cancel + /list clear.
|
|
860
|
+
if (sub === "cancel") {
|
|
861
|
+
const waiting = listQueue().length;
|
|
862
|
+
const activeIsListItem = state.goal?.policy === "list" && (state.goal.status === "active" || state.goal.status === "paused");
|
|
863
|
+
if (waiting === 0 && !activeIsListItem) {
|
|
864
|
+
ctx.ui.notify("No list to cancel — nothing waiting, and the active goal (if any) isn't a list item. /goal cancel aborts a standalone goal.", "info");
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
const dropped = waiting;
|
|
868
|
+
state = { ...state, list: [] };
|
|
869
|
+
persistState(ctx);
|
|
870
|
+
if (activeIsListItem) {
|
|
871
|
+
archiveCurrentGoal(ctx, "aborted", "list cancelled");
|
|
872
|
+
ctx.abort();
|
|
873
|
+
}
|
|
874
|
+
appendLedger(ctx.cwd, "list_cancelled", { abortedActive: activeIsListItem, dropped });
|
|
875
|
+
ctx.ui.notify(
|
|
876
|
+
`List cancelled: ${activeIsListItem ? "active item aborted + " : ""}${dropped} waiting item(s) dropped.${!activeIsListItem && state.goal && state.goal.status === "active" ? " Active goal is not a list item — untouched (/goal cancel for that)." : ""}`,
|
|
877
|
+
"info",
|
|
878
|
+
);
|
|
853
879
|
return;
|
|
854
880
|
}
|
|
855
881
|
|
|
@@ -1452,6 +1478,8 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
1452
1478
|
at: nowIso(),
|
|
1453
1479
|
approved: result.approved,
|
|
1454
1480
|
disapproved: result.disapproved,
|
|
1481
|
+
impossible: result.impossible,
|
|
1482
|
+
impossibleReason: result.impossibleReason,
|
|
1455
1483
|
model: result.model,
|
|
1456
1484
|
thinkingLevel: result.thinkingLevel,
|
|
1457
1485
|
report: result.output,
|
|
@@ -1496,6 +1524,30 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
1496
1524
|
return { content: [{ type: "text", text: `Goal approved by auditor ${result.model}.` }], details: {} };
|
|
1497
1525
|
}
|
|
1498
1526
|
|
|
1527
|
+
// IMPOSSIBLE (v0.24.2, Claude-Code lesson): the auditor's escape hatch
|
|
1528
|
+
// for goals that can NEVER be satisfied as stated. Not a disapproval —
|
|
1529
|
+
// continuing would burn tokens on a provably unwinnable objective.
|
|
1530
|
+
// Bounded and surfaced: the goal pauses and the user decides.
|
|
1531
|
+
if (result.impossible) {
|
|
1532
|
+
const reason = result.impossibleReason || "(no reason given)";
|
|
1533
|
+
updateGoal({
|
|
1534
|
+
status: "paused",
|
|
1535
|
+
auditHistory: history,
|
|
1536
|
+
pauseReason: `auditor verdict: IMPOSSIBLE — ${reason}`,
|
|
1537
|
+
pauseSuggestedAction: "The auditor says this goal can never be satisfied as stated. /goal tweak the objective (or /goal cancel), then /goal resume.",
|
|
1538
|
+
}, ctx);
|
|
1539
|
+
ctx.ui.notify(`Auditor: goal IMPOSSIBLE — ${reason}. Goal paused; /goal tweak or /goal cancel, then /goal resume.`, "warning");
|
|
1540
|
+
appendLedger(ctx.cwd, "goal_paused", { reason: `auditor impossible: ${reason}` });
|
|
1541
|
+
notifyExternal(ctx, `Goal paused (auditor: impossible): ${reason.slice(0, 120)}`);
|
|
1542
|
+
return {
|
|
1543
|
+
content: [{
|
|
1544
|
+
type: "text",
|
|
1545
|
+
text: `The auditor's verdict is IMPOSSIBLE: ${reason}\n\nThis is not a disapproval — the auditor says the objective can never be satisfied as stated. The goal is now PAUSED. Do not call complete_goal again. Report the verdict to the user and suggest /goal tweak (narrow or correct the objective) or /goal cancel.`,
|
|
1546
|
+
}],
|
|
1547
|
+
details: {},
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1499
1551
|
// THREE-WAY SPLIT (v0.9.9): infrastructure failure is NOT a verdict.
|
|
1500
1552
|
// The wild-caught case: 6 silent "disapprovals" that were really a dead
|
|
1501
1553
|
// auditor model. The agent must be able to tell the difference.
|
|
@@ -1542,6 +1594,30 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
1542
1594
|
const noContractHint = state.goal.verificationContract?.trim()
|
|
1543
1595
|
? ""
|
|
1544
1596
|
: "\n\nNote: this goal has no verification contract, so the auditor inferred done-criteria from the objective text. For sharper verdicts, /goal tweak the objective to add a 'Done when: ...' clause.";
|
|
1597
|
+
// v0.24.2 (Claude-Code lesson — their stop-hook blocks cap at 8): a
|
|
1598
|
+
// goal the auditor can NEVER approve used to re-continue forever.
|
|
1599
|
+
// auditCap consecutive disapprovals → pause + notify, bounded and
|
|
1600
|
+
// surfaced like every other stop in this stack.
|
|
1601
|
+
const auditCap = loadSettings(ctx.cwd).auditCap ?? 3;
|
|
1602
|
+
const trailingDisapprovals = countTrailingDisapprovals(history);
|
|
1603
|
+
if (auditCap > 0 && trailingDisapprovals >= auditCap) {
|
|
1604
|
+
updateGoal({
|
|
1605
|
+
status: "paused",
|
|
1606
|
+
auditHistory: history,
|
|
1607
|
+
pauseReason: `auditor disapproved ${trailingDisapprovals}× consecutively (cap ${auditCap})`,
|
|
1608
|
+
pauseSuggestedAction: "Read the audit history (/goal status), fix the actual gap or /goal tweak the objective, then /goal resume. Raise the cap with /glla auditcap=N.",
|
|
1609
|
+
}, ctx);
|
|
1610
|
+
ctx.ui.notify(`Goal paused: auditor disapproved ${trailingDisapprovals}× consecutively (cap ${auditCap}). /goal status for the reports; /goal resume to continue.`, "warning");
|
|
1611
|
+
appendLedger(ctx.cwd, "goal_paused", { reason: `disapproval cap: ${trailingDisapprovals} consecutive (cap ${auditCap})` });
|
|
1612
|
+
notifyExternal(ctx, `Goal paused: ${trailingDisapprovals} consecutive auditor disapprovals`);
|
|
1613
|
+
return {
|
|
1614
|
+
content: [{
|
|
1615
|
+
type: "text",
|
|
1616
|
+
text: `The auditor has now disapproved ${trailingDisapprovals} times in a row (cap ${auditCap}). The goal is PAUSED — continuing to re-attempt without addressing the pattern wastes tokens. Latest report (first 800 chars):\n${result.output.slice(0, 800)}\n\nDo not call complete_goal again. Summarize the repeated objections for the user and ask how to proceed (/goal status shows all reports; /goal resume resumes).`,
|
|
1617
|
+
}],
|
|
1618
|
+
details: {},
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1545
1621
|
updateGoal({
|
|
1546
1622
|
status: "active",
|
|
1547
1623
|
auditHistory: history,
|
|
@@ -2121,6 +2197,8 @@ interface Settings {
|
|
|
2121
2197
|
/** on → restored goals/loops/lists auto-resume even in fresh sessions
|
|
2122
2198
|
* (unattended rigs). Default off: restore holds until /goal resume. */
|
|
2123
2199
|
autoResume?: boolean;
|
|
2200
|
+
/** v0.24.2: pause the goal after N consecutive auditor disapprovals (0 = unlimited). Default 3. */
|
|
2201
|
+
auditCap?: number;
|
|
2124
2202
|
/** on → propose_* drafts activate WITHOUT the Confirm dialog and the
|
|
2125
2203
|
* interview floor is skipped — the seed carries the intent (unattended
|
|
2126
2204
|
* rigs). Default off: nothing activates before the user confirms. */
|
|
@@ -2169,7 +2247,7 @@ function settingsProvenance(cwd: string): Record<keyof Settings, { value: unknow
|
|
|
2169
2247
|
const glob = readSettingsFile(globalSettingsPath());
|
|
2170
2248
|
const effective = loadSettings(cwd);
|
|
2171
2249
|
const out: Record<string, { value: unknown; source: "project" | "global" | "default" }> = {};
|
|
2172
|
-
const keys: Array<keyof Settings> = ["auditorModel", "auditorThinkingLevel", "notifyCmd", "tokenLimit", "wedgeAlertMinutes", "autoResume", "autoAcceptDrafts"];
|
|
2250
|
+
const keys: Array<keyof Settings> = ["auditorModel", "auditorThinkingLevel", "notifyCmd", "tokenLimit", "wedgeAlertMinutes", "autoResume", "autoAcceptDrafts", "auditCap"];
|
|
2173
2251
|
for (const k of keys) {
|
|
2174
2252
|
if ((proj as Record<string, unknown>)[k] !== undefined) out[k] = { value: (proj as any)[k], source: "project" };
|
|
2175
2253
|
else if ((glob as Record<string, unknown>)[k] !== undefined) out[k] = { value: (glob as any)[k], source: "global" };
|
|
@@ -2340,6 +2418,7 @@ async function cmdSettings(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
2340
2418
|
fmt("tokenLimit", "tokenLimit"),
|
|
2341
2419
|
fmt("autoResume", "autoResume"),
|
|
2342
2420
|
fmt("autoAcceptDrafts", "autoAccept"),
|
|
2421
|
+
fmt("auditCap", "auditCap"),
|
|
2343
2422
|
`\nglobal: ${globalSettingsPath()}`,
|
|
2344
2423
|
`project: ${projectSettingsPath(ctx.cwd)}`,
|
|
2345
2424
|
`Set with: /glla key=value (global) · /glla project key=value (project override)`,
|
|
@@ -2412,6 +2491,19 @@ async function cmdSettings(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
2412
2491
|
} else {
|
|
2413
2492
|
ctx.ui.notify(`autoaccept must be on or off, got: ${value}`, "warning");
|
|
2414
2493
|
}
|
|
2494
|
+
} else if (key === "auditcap") {
|
|
2495
|
+
if (["off", "unset", "default"].includes(value)) {
|
|
2496
|
+
patch.auditCap = undefined;
|
|
2497
|
+
changed = true;
|
|
2498
|
+
} else {
|
|
2499
|
+
const n = Number.parseInt(value, 10);
|
|
2500
|
+
if (Number.isInteger(n) && n >= 0) {
|
|
2501
|
+
patch.auditCap = n;
|
|
2502
|
+
changed = true;
|
|
2503
|
+
} else {
|
|
2504
|
+
ctx.ui.notify(`auditcap must be a non-negative integer (0 = unlimited), got: ${value}`, "warning");
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2415
2507
|
} else if (key === "thinking" || key === "auditorthinkinglevel") {
|
|
2416
2508
|
if (["off", "minimal", "low", "medium", "high", "xhigh"].includes(value)) {
|
|
2417
2509
|
patch.auditorThinkingLevel = value as Settings["auditorThinkingLevel"];
|
|
@@ -2543,19 +2635,21 @@ export default function (pi: ExtensionAPI): void {
|
|
|
2543
2635
|
["notify=", "desktop push command: /glla notify='notify-send pi \"$1\"'"],
|
|
2544
2636
|
["tokenlimit=", "per-goal token budget (0 = off): /glla tokenlimit=2000000"],
|
|
2545
2637
|
["autoresume=", "on: auto-resume held goals/loops in fresh sessions"],
|
|
2638
|
+
["auditcap=", "N: pause goal after N consecutive auditor disapprovals (default 3, 0 = unlimited)"],
|
|
2546
2639
|
["autoaccept=", "on: drafts activate without the Confirm dialog (unattended rigs)"],
|
|
2547
2640
|
["project", "write a project override: /glla project key=value"],
|
|
2548
2641
|
]),
|
|
2549
2642
|
handler: settingsHandler,
|
|
2550
2643
|
});
|
|
2551
2644
|
pi.registerCommand("list", {
|
|
2552
|
-
description: "Loop 2: the list of audited goals — order is the default, not the law. /list <describe tasks or name a plan file> (dumps get shaped into items, files import, 'Done when:' adds directly) | /list show | /list resume | /list next [n] | /list remove <n> | /list clear",
|
|
2645
|
+
description: "Loop 2: the list of audited goals — order is the default, not the law. /list <describe tasks or name a plan file> (dumps get shaped into items, files import, 'Done when:' adds directly) | /list show | /list resume | /list next [n] | /list remove <n> | /list clear | /list cancel",
|
|
2553
2646
|
getArgumentCompletions: completions([
|
|
2554
2647
|
["show", "display the waiting items"],
|
|
2555
2648
|
["resume", "resume the paused list item (the list's head)"],
|
|
2556
2649
|
["next", "activate the next item (or /list next <n> for position n)"],
|
|
2557
2650
|
["remove", "remove an item: /list remove <n>"],
|
|
2558
2651
|
["clear", "empty the list"],
|
|
2652
|
+
["cancel", "stop the whole list: abort the active item + drop all waiting"],
|
|
2559
2653
|
]),
|
|
2560
2654
|
handler: (args: string, ctx: ExtensionContext) => { rememberCtx(ctx); return cmdList(args, ctx); },
|
|
2561
2655
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.2",
|
|
4
4
|
"description": "Goal. Loop. Audit. Done. — 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 — only the read tools needed to verify your goal.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "dracon",
|