pi-goal-list-loop-audit 0.27.6 → 0.27.7
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 +26 -10
- package/extensions/reviewer.ts +33 -7
- package/package.json +1 -1
package/extensions/loops/goal.ts
CHANGED
|
@@ -679,7 +679,7 @@ function archiveCurrentGoal(ctx: ExtensionContext, status: Status, stopReason?:
|
|
|
679
679
|
function fireReviewer(
|
|
680
680
|
ctx: ExtensionContext,
|
|
681
681
|
source: { kind: "goal" | "list"; goalId: string; objective: string; terminal: string },
|
|
682
|
-
opts: { manual?: boolean; mode?: "default" | "auto" | "report" } = {},
|
|
682
|
+
opts: { manual?: boolean; mode?: "off" | "default" | "auto" | "aggressive" | "report" } = {},
|
|
683
683
|
): void {
|
|
684
684
|
try {
|
|
685
685
|
const settings = loadSettings(ctx.cwd);
|
|
@@ -3068,13 +3068,16 @@ async function cmdReview(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
3068
3068
|
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
3069
3069
|
const id = parts[0] ?? "";
|
|
3070
3070
|
const modeArg = parts[1];
|
|
3071
|
-
const
|
|
3071
|
+
const validModes = ["off", "default", "auto", "aggressive", "report"] as const;
|
|
3072
|
+
const mode = (validModes as readonly string[]).includes(modeArg ?? "")
|
|
3073
|
+
? (modeArg as typeof validModes[number])
|
|
3074
|
+
: undefined;
|
|
3072
3075
|
if (modeArg && !mode) {
|
|
3073
|
-
ctx.ui.notify(`Unknown mode "${modeArg}" — use auto |
|
|
3076
|
+
ctx.ui.notify(`Unknown mode "${modeArg}" — use off | default | auto | aggressive | report.`, "warning");
|
|
3074
3077
|
return;
|
|
3075
3078
|
}
|
|
3076
3079
|
if (!id) {
|
|
3077
|
-
ctx.ui.notify(
|
|
3080
|
+
ctx.ui.notify(`Usage: /review <goal-id> [${validModes.join("|")}] — see /goal archive for ids.`, "info");
|
|
3078
3081
|
return;
|
|
3079
3082
|
}
|
|
3080
3083
|
// Resolve the id against the archive (suffix match allowed).
|
|
@@ -3098,15 +3101,22 @@ async function cmdReview(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
3098
3101
|
fireReviewer(ctx, { kind: "goal", goalId, objective, terminal: "goal-complete" }, { manual: true, mode });
|
|
3099
3102
|
}
|
|
3100
3103
|
|
|
3101
|
-
/** v0.
|
|
3104
|
+
/** v0.27.5: /glla reviewer | postaudit — the post-completion audit config menu
|
|
3105
|
+
* (project-scoped). Reads the dual-write settings (postaudit wins over the
|
|
3106
|
+
* legacy reviewer key), and writes back to whichever key was read first —
|
|
3107
|
+
* so we don't drift two parallel config blocks. */
|
|
3102
3108
|
async function cmdReviewerSettings(ctx: ExtensionContext): Promise<void> {
|
|
3109
|
+
const settings = loadSettings(ctx.cwd);
|
|
3110
|
+
const block = (settings.postaudit ?? settings.reviewer) as Partial<ReviewerConfig> | undefined;
|
|
3111
|
+
const settingsKey: "postaudit" | "reviewer" = settings.postaudit !== undefined ? "postaudit" : "reviewer";
|
|
3103
3112
|
if (!ctx.hasUI) {
|
|
3104
|
-
const cfg = resolveReviewerConfig(
|
|
3105
|
-
ctx.ui.notify(
|
|
3113
|
+
const cfg = resolveReviewerConfig(block);
|
|
3114
|
+
ctx.ui.notify(`${settingsKey} (project): ${JSON.stringify(cfg, null, 2)}`, "info");
|
|
3106
3115
|
return;
|
|
3107
3116
|
}
|
|
3108
|
-
const load = () => resolveReviewerConfig(loadSettings(ctx.cwd)
|
|
3109
|
-
const save = (patch: Partial<ReviewerConfig>) =>
|
|
3117
|
+
const load = () => resolveReviewerConfig(loadSettings(ctx.cwd)[settingsKey] as Partial<ReviewerConfig> | undefined);
|
|
3118
|
+
const save = (patch: Partial<ReviewerConfig>) =>
|
|
3119
|
+
saveSettings("project", ctx.cwd, { [settingsKey]: { ...load(), ...patch } as Record<string, unknown> });
|
|
3110
3120
|
for (;;) {
|
|
3111
3121
|
const cfg = load();
|
|
3112
3122
|
let choice: string | undefined;
|
|
@@ -3118,7 +3128,13 @@ async function cmdReviewerSettings(ctx: ExtensionContext): Promise<void> {
|
|
|
3118
3128
|
if (!choice || choice === "Done") return;
|
|
3119
3129
|
try {
|
|
3120
3130
|
if (choice.startsWith("Enabled")) save({ enabled: !cfg.enabled });
|
|
3121
|
-
else if (choice.startsWith("Mode"))
|
|
3131
|
+
else if (choice.startsWith("Mode")) {
|
|
3132
|
+
// v0.27.5: 5-state cycle off → default → auto → aggressive → report → off
|
|
3133
|
+
const order: Array<"off" | "default" | "auto" | "aggressive" | "report"> = ["off", "default", "auto", "aggressive", "report"];
|
|
3134
|
+
const i = order.indexOf(cfg.mode as typeof order[number]);
|
|
3135
|
+
const next = order[(i + 1) % order.length]!;
|
|
3136
|
+
save({ mode: next });
|
|
3137
|
+
}
|
|
3122
3138
|
else if (choice.startsWith("Leverage mode")) save({ leverageMode: cfg.leverageMode === "fix-without-confirm" ? "confirm-all" : "fix-without-confirm" });
|
|
3123
3139
|
else if (choice.startsWith("Fire on goal-complete")) save({ fireOn: cfg.fireOn.includes("goal-complete") ? cfg.fireOn.filter((e) => e !== "goal-complete") : [...cfg.fireOn, "goal-complete"] });
|
|
3124
3140
|
else if (choice.startsWith("Fire on list-complete")) save({ fireOn: cfg.fireOn.includes("list-complete") ? cfg.fireOn.filter((e) => e !== "list-complete") : [...cfg.fireOn, "list-complete"] });
|
package/extensions/reviewer.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import * as fs from "node:fs";
|
|
16
16
|
import * as path from "node:path";
|
|
17
17
|
|
|
18
|
-
export type ReviewerMode = "default" | "auto" | "report";
|
|
18
|
+
export type ReviewerMode = "off" | "default" | "auto" | "aggressive" | "report";
|
|
19
19
|
|
|
20
20
|
export interface ReviewerConfig {
|
|
21
21
|
enabled: boolean;
|
|
@@ -203,6 +203,8 @@ export interface ReviewerOutcome {
|
|
|
203
203
|
reportPath?: string;
|
|
204
204
|
enqueued: number;
|
|
205
205
|
proposed: number;
|
|
206
|
+
/** v0.27.5: the cascade step that actually fired (notify-and-idle | convert-findings-to-list | queue-leftovers | fire-audit-on-clean | propose-goal | aggressive-relaunch | report-only) — surfaces in /goal status and tests. */
|
|
207
|
+
cascadeStep?: string;
|
|
206
208
|
}
|
|
207
209
|
|
|
208
210
|
export const REVIEWER_REFIRE_WINDOW_MS = 5 * 60_000;
|
|
@@ -215,6 +217,9 @@ export function runReviewer(
|
|
|
215
217
|
): ReviewerOutcome {
|
|
216
218
|
const none = (suppressedReason: string): ReviewerOutcome => ({ fired: false, suppressedReason, enqueued: 0, proposed: 0 });
|
|
217
219
|
if (!config.enabled && !deps.manual) return none("reviewer disabled");
|
|
220
|
+
// v0.27.5: "off" mode is the user-friendly way to silence the postaudit
|
|
221
|
+
// — equivalent to enabled=false but exposed via the postaudit menu.
|
|
222
|
+
if (config.mode === "off" && !deps.manual) return none("postaudit mode = off");
|
|
218
223
|
const event = source.kind === "goal" ? `${source.terminal}` : "list-complete";
|
|
219
224
|
if (!deps.manual) {
|
|
220
225
|
if (config.doNotFireOn.includes(event)) return none(`doNotFireOn: ${event}`);
|
|
@@ -243,7 +248,8 @@ export function runReviewer(
|
|
|
243
248
|
let enqueued = 0;
|
|
244
249
|
let proposed = 0;
|
|
245
250
|
let cascadeStep = "notify-and-idle";
|
|
246
|
-
const auto = config.mode === "auto";
|
|
251
|
+
const auto = config.mode === "auto" || config.mode === "aggressive";
|
|
252
|
+
const aggressive = config.mode === "aggressive";
|
|
247
253
|
const reportOnly = config.mode === "report";
|
|
248
254
|
|
|
249
255
|
// Cascade: findings → list items (leverage: fix-without-confirm).
|
|
@@ -255,8 +261,22 @@ export function runReviewer(
|
|
|
255
261
|
}
|
|
256
262
|
// Architectural findings: default mode → /goal proposal WITH Confirm;
|
|
257
263
|
// auto mode → /list items (the auto-loop rolls straight into them).
|
|
264
|
+
// aggressive mode → enqueue AND relaunch as the next active goal
|
|
265
|
+
// (skips both Confirm and the queue — the unattended rig never stops).
|
|
258
266
|
if (architectural.length > 0 && !reportOnly) {
|
|
259
|
-
if (
|
|
267
|
+
if (aggressive) {
|
|
268
|
+
deps.enqueueListItems(architectural.map((f) => f.text));
|
|
269
|
+
// v0.27.5 aggressive: also propose the FIRST architectural finding
|
|
270
|
+
// as a relaunch so the queue gets burned through even when the
|
|
271
|
+
// unattended rig can't Confirm.
|
|
272
|
+
deps.proposeGoal(
|
|
273
|
+
architectural[0]!.text,
|
|
274
|
+
`aggressive postaudit: relaunching as /goal without Confirm (${architectural.length} architectural findings total)`,
|
|
275
|
+
);
|
|
276
|
+
enqueued += architectural.length;
|
|
277
|
+
proposed += 1;
|
|
278
|
+
cascadeStep = "aggressive-relaunch";
|
|
279
|
+
} else if (auto) {
|
|
260
280
|
deps.enqueueListItems(architectural.map((f) => f.text));
|
|
261
281
|
enqueued += architectural.length;
|
|
262
282
|
cascadeStep = convertStep;
|
|
@@ -272,16 +292,22 @@ export function runReviewer(
|
|
|
272
292
|
// Clean completion → audit: default mode proposes a /goal (Confirm);
|
|
273
293
|
// auto mode enqueues the audit as a /list item (no Confirm — the
|
|
274
294
|
// cascade keeps rolling until the findings run dry).
|
|
295
|
+
// aggressive mode → relaunch the audit goal directly (no Confirm).
|
|
275
296
|
if (findings.length === 0 && config.cascade.includes("fire-audit-on-clean") && !reportOnly) {
|
|
276
297
|
const auditObjective = `Post-completion regression scan after ${source.goalId} (${config.auditScope})`;
|
|
277
|
-
if (
|
|
298
|
+
if (aggressive) {
|
|
299
|
+
deps.proposeGoal(auditObjective, "aggressive postaudit: clean completion — relaunching the regression scan as /goal");
|
|
300
|
+
proposed++;
|
|
301
|
+
cascadeStep = "aggressive-relaunch";
|
|
302
|
+
} else if (auto) {
|
|
278
303
|
deps.enqueueListItems([auditObjective]);
|
|
279
304
|
enqueued++;
|
|
305
|
+
cascadeStep = "fire-audit-on-clean";
|
|
280
306
|
} else {
|
|
281
307
|
deps.proposeGoal(auditObjective, "reviewer: completion looks clean — firing the audit step");
|
|
282
308
|
proposed++;
|
|
309
|
+
cascadeStep = "fire-audit-on-clean";
|
|
283
310
|
}
|
|
284
|
-
cascadeStep = "fire-audit-on-clean";
|
|
285
311
|
}
|
|
286
312
|
if (reportOnly) cascadeStep = "report-only";
|
|
287
313
|
|
|
@@ -311,7 +337,7 @@ export function runReviewer(
|
|
|
311
337
|
if (strategic.length > 0) {
|
|
312
338
|
deps.notify(`Reviewer: ${strategic.length} strategic finding(s) need YOUR call — see the report's Strategic section.`, "warning");
|
|
313
339
|
}
|
|
314
|
-
return { fired: true, report, reportPath, enqueued, proposed };
|
|
340
|
+
return { fired: true, report, reportPath, enqueued, proposed, cascadeStep };
|
|
315
341
|
}
|
|
316
342
|
|
|
317
343
|
/** /glla reviewer menu options, derived from the config — extracted so
|
|
@@ -319,7 +345,7 @@ export function runReviewer(
|
|
|
319
345
|
export function reviewerMenuOptions(cfg: ReviewerConfig): string[] {
|
|
320
346
|
return [
|
|
321
347
|
`Enabled — ${cfg.enabled ? "ON" : "OFF"}`,
|
|
322
|
-
`Mode — ${cfg.mode} (default = Confirm-gated · auto = auto-loop, no Confirms · report = report only)`,
|
|
348
|
+
`Mode — ${cfg.mode} (off = silenced · default = Confirm-gated · auto = auto-loop, no Confirms · aggressive = auto + relaunch · report = report only)`,
|
|
323
349
|
`Leverage mode — ${cfg.leverageMode} (bug/refactor findings)`,
|
|
324
350
|
`Fire on goal-complete — ${cfg.fireOn.includes("goal-complete") ? "ON" : "OFF"}`,
|
|
325
351
|
`Fire on list-complete — ${cfg.fireOn.includes("list-complete") ? "ON" : "OFF"}`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.7",
|
|
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",
|