pi-goal-list-loop-audit 0.28.29 → 0.28.31
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.
|
@@ -276,11 +276,16 @@ function goalLines(g: Goal, state: State, audit: AuditDisplayProgress | null | u
|
|
|
276
276
|
// queue work were a standalone goal.
|
|
277
277
|
const isList = g.policy === "list";
|
|
278
278
|
const statusWord = g.status === "active" ? paint(theme, "success", "active") : g.status;
|
|
279
|
+
// v0.28.30: the status line ALWAYS names the type (user note: "I don't
|
|
280
|
+
// always see the type — I'd need to scroll up to see if goal/list/loop").
|
|
281
|
+
// Before, only list items were named; a plain goal's card said "paused ·
|
|
282
|
+
// 3m" with no type word. The loop surface has its own card.
|
|
283
|
+
const typeWord = isList ? "list item · " : "goal · ";
|
|
279
284
|
// Token segment only when a budget is set (v0.22.0): the guard is opt-in,
|
|
280
285
|
// and "0/0 tok" carried no information when off.
|
|
281
286
|
const tokenLimit = g.usage?.tokensLimit ?? 0;
|
|
282
287
|
const tokens = tokenLimit > 0 ? ` · ${paint(theme, "dim", `${fmtTokens(g.usage?.tokensUsed ?? 0)}/${fmtTokens(tokenLimit)} tok`)}` : "";
|
|
283
|
-
const lines = [head, `├─ ${
|
|
288
|
+
const lines = [head, `├─ ${typeWord}${statusWord} · ${fmtElapsed(now - Date.parse(g.createdAt))}${tokens}`];
|
|
284
289
|
if (g.status === "auditing") {
|
|
285
290
|
lines.push(`├─ auditor: ${audit?.label ?? "running"}${audit?.currentTool ? ` · ${truncate(audit.currentTool, 30)}` : ""}`);
|
|
286
291
|
// v0.25.4: auditor-quiet stall — progress events stopped arriving
|
package/extensions/loops/goal.ts
CHANGED
|
@@ -551,8 +551,8 @@ function escalateSendRearmStorm(ctx: ExtensionContext, kind: "continuation" | "l
|
|
|
551
551
|
pauseReason: `send-retry storm: ${mins}m of re-arms with no session activity for ${silent}m — the session never went idle for the continuation`,
|
|
552
552
|
pauseSuggestedAction: "The session produced no events while the send retried (wedged queue). Restart pi, then /goal resume.",
|
|
553
553
|
}, ctx);
|
|
554
|
-
ctx.ui.notify(
|
|
555
|
-
notifyExternal(ctx,
|
|
554
|
+
ctx.ui.notify(`${goalNoun()} paused: send-retry storm (${mins}m, session silent ${silent}m). Restart pi, then /goal resume.`, "warning");
|
|
555
|
+
notifyExternal(ctx, `${goalNoun()} paused: send-retry storm.`);
|
|
556
556
|
}
|
|
557
557
|
}
|
|
558
558
|
|
|
@@ -575,8 +575,8 @@ function escalateStallNow(ctx: ExtensionContext, threshold: number): boolean {
|
|
|
575
575
|
pauseReason: `stalled: ${threshold} continuation refires landed no turn`,
|
|
576
576
|
pauseSuggestedAction: "The continuation chain is broken in this process (wedged message queue or stale API). Restart pi, then /goal resume.",
|
|
577
577
|
}, ctx);
|
|
578
|
-
ctx.ui.notify(
|
|
579
|
-
notifyExternal(ctx,
|
|
578
|
+
ctx.ui.notify(`${goalNoun()} paused: ${threshold} refires produced no turn. Restart pi, then /goal resume.`, "warning");
|
|
579
|
+
notifyExternal(ctx, `${goalNoun()} paused: stalled (continuation not landing).`);
|
|
580
580
|
return true;
|
|
581
581
|
}
|
|
582
582
|
return true;
|
|
@@ -659,7 +659,7 @@ function heartbeatTick(): void {
|
|
|
659
659
|
})
|
|
660
660
|
) {
|
|
661
661
|
lastWedgeAlertAt = Date.now();
|
|
662
|
-
const msg =
|
|
662
|
+
const msg = `${goalNoun()} appears wedged: no activity for ${Math.round((Date.now() - lastActivityAt) / 60_000)}m while the session is busy — likely a hung command (test/build/dev server without a timeout). Check the session; Esc kills a stuck tool call.`;
|
|
663
663
|
appendLedger(ctx.cwd, "wedge_alert", { silentMs: Date.now() - lastActivityAt });
|
|
664
664
|
ctx.ui.notify(msg, "warning");
|
|
665
665
|
notifyExternal(ctx, msg);
|
|
@@ -910,6 +910,9 @@ let persistenceDegradedNotified = false;
|
|
|
910
910
|
|
|
911
911
|
/** v0.28.11 (U9): objective-first notifies — truncate long objectives. */
|
|
912
912
|
const shortObj = (s: string): string => (s.length > 90 ? `${s.slice(0, 87)}…` : s);
|
|
913
|
+
/** v0.28.30: terminology — a list item is not a goal (user note: "we seem
|
|
914
|
+
* to call everything goal"). User-facing pause/abort notifies name the policy. */
|
|
915
|
+
const goalNoun = (): string => (state.goal?.policy === "list" ? "List item" : "Goal");
|
|
913
916
|
function notifyPersistenceState(ctx: ExtensionContext): void {
|
|
914
917
|
if (isPersistenceDegraded() && !persistenceDegradedNotified) {
|
|
915
918
|
persistenceDegradedNotified = true;
|
|
@@ -1521,7 +1524,7 @@ async function cmdCancel(ctx: ExtensionContext): Promise<void> {
|
|
|
1521
1524
|
}
|
|
1522
1525
|
archiveCurrentGoal(ctx, "aborted", "user cancelled");
|
|
1523
1526
|
ctx.abort();
|
|
1524
|
-
ctx.ui.notify(
|
|
1527
|
+
ctx.ui.notify(`${goalNoun()} aborted.${isLoopActive() ? " A loop is still active — /loop stop ends it." : ""}`, "info");
|
|
1525
1528
|
}
|
|
1526
1529
|
|
|
1527
1530
|
// ---- v0.28.23: decision picker popup ----
|
|
@@ -2837,8 +2840,8 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
2837
2840
|
pauseSuggestedAction: "Fix the auditor model (/glla model=provider/id) or restart pi, then /goal resume. Your work was NOT judged.",
|
|
2838
2841
|
}, ctx);
|
|
2839
2842
|
appendLedger(ctx.cwd, "goal_paused", { reason: `auditor infra streak ${infraStreak}: ${result.error.slice(0, 120)}` });
|
|
2840
|
-
ctx.ui.notify(
|
|
2841
|
-
notifyExternal(ctx,
|
|
2843
|
+
ctx.ui.notify(`${goalNoun()} paused: auditor infrastructure failed ${infraStreak}× in a row. Fix the auditor model (/glla model=...), then /goal resume.`, "warning");
|
|
2844
|
+
notifyExternal(ctx, `${goalNoun()} paused: auditor infrastructure ${infraStreak}× — model likely broken.`);
|
|
2842
2845
|
return {
|
|
2843
2846
|
content: [{
|
|
2844
2847
|
type: "text",
|
|
@@ -2945,7 +2948,7 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
2945
2948
|
pauseReason: `auditor disapproved ${trailingDisapprovals}× consecutively (cap ${auditCap})`,
|
|
2946
2949
|
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.",
|
|
2947
2950
|
}, ctx);
|
|
2948
|
-
ctx.ui.notify(
|
|
2951
|
+
ctx.ui.notify(`${goalNoun()} paused: auditor disapproved ${trailingDisapprovals}× consecutively (cap ${auditCap}). /goal status for the reports; /goal resume to continue.`, "warning");
|
|
2949
2952
|
maybeDecisionPopup(ctx);
|
|
2950
2953
|
appendLedger(ctx.cwd, "goal_paused", { reason: `disapproval cap: ${trailingDisapprovals} consecutive (cap ${auditCap})` });
|
|
2951
2954
|
notifyExternal(ctx, `Goal paused: ${trailingDisapprovals} consecutive auditor disapprovals`);
|
|
@@ -3005,8 +3008,8 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
3005
3008
|
// action. Before, the action only appeared in /goal status and the
|
|
3006
3009
|
// widget truncated both at ~60 chars, so decision-pauses ("choose a
|
|
3007
3010
|
// or b") reached the user as an unreadable fragment.
|
|
3008
|
-
ctx.ui.notify(
|
|
3009
|
-
notifyExternal(ctx,
|
|
3011
|
+
ctx.ui.notify(`${goalNoun()} paused: ${p.reason}${p.suggestedAction ? `\n\n→ ${p.suggestedAction}` : ""}`, "info");
|
|
3012
|
+
notifyExternal(ctx, `${goalNoun()} paused: ${(p.suggestedAction ? `${p.reason} → ${p.suggestedAction}` : p.reason).slice(0, 200)}`);
|
|
3010
3013
|
return { content: [{ type: "text", text: "Goal paused. /goal resume to continue." }], details: {} };
|
|
3011
3014
|
},
|
|
3012
3015
|
}));
|
|
@@ -4182,6 +4185,64 @@ function cmdLog(args: string, ctx: ExtensionContext): void {
|
|
|
4182
4185
|
ctx.ui.notify(`Ledger tail (last ${tail.length}${all ? "" : " non-noise"} events — /glla log <N> for more, /glla log all to include noise):\n${lines.join("\n")}`, "info");
|
|
4183
4186
|
}
|
|
4184
4187
|
|
|
4188
|
+
/**
|
|
4189
|
+
* v0.28.31: /glla reset — ONE confirmed command that leaves a project with
|
|
4190
|
+
* zero live glla state. User directive: "make sure we only have one goal or
|
|
4191
|
+
* loop or list at a time — many of my older projects have leftovers" (the
|
|
4192
|
+
* fleet scan found queued lists up to 56 deep, held loops at iter 50, and
|
|
4193
|
+
* paused goals across ~10 projects). The goal is archived HONESTLY (aborted
|
|
4194
|
+
* — lands in goals/ + the archive, reviewer's abort-suppression applies),
|
|
4195
|
+
* the list is cleared, the loop record is wiped after a graceful stop.
|
|
4196
|
+
* History stays in .pi-glla; only the live state goes.
|
|
4197
|
+
*/
|
|
4198
|
+
async function cmdGllaReset(ctx: ExtensionContext): Promise<void> {
|
|
4199
|
+
const g = state.goal;
|
|
4200
|
+
const live = g && (g.status === "active" || g.status === "paused" || g.status === "auditing");
|
|
4201
|
+
const n = listQueue().length;
|
|
4202
|
+
const loop = state.loop;
|
|
4203
|
+
if (!g && n === 0 && !loop) {
|
|
4204
|
+
ctx.ui.notify("glla state is already clean — no goal, no list, no loop.", "info");
|
|
4205
|
+
return;
|
|
4206
|
+
}
|
|
4207
|
+
const parts: string[] = [];
|
|
4208
|
+
if (live) parts.push(`goal archived as aborted: ${g!.objective.replace(/\s+/g, " ").slice(0, 70)}`);
|
|
4209
|
+
else if (g) parts.push(`terminal goal record cleared (${g.status})`);
|
|
4210
|
+
if (n > 0) parts.push(`list cleared (${n} item${n === 1 ? "" : "s"})`);
|
|
4211
|
+
if (loop) parts.push(`loop ${loop.active ? "stopped" : "cleared"} (iter ${loop.iteration}${loop.bestValue !== null && loop.bestValue !== undefined ? `, best ${loop.bestValue}` : ""})`);
|
|
4212
|
+
if (ctx.hasUI) {
|
|
4213
|
+
try {
|
|
4214
|
+
const ok = await ctx.ui.confirm("Reset glla state?", `${parts.map((p) => ` ${p}`).join("\n")}\n\nHistory stays in .pi-glla (archive + ledger); the live state is wiped.`);
|
|
4215
|
+
if (!ok) {
|
|
4216
|
+
ctx.ui.notify("Reset cancelled.", "info");
|
|
4217
|
+
return;
|
|
4218
|
+
}
|
|
4219
|
+
} catch {
|
|
4220
|
+
ctx.ui.notify("Reset cancelled.", "info");
|
|
4221
|
+
return;
|
|
4222
|
+
}
|
|
4223
|
+
}
|
|
4224
|
+
appendLedger(ctx.cwd, "glla_reset", { goalId: live ? g!.id : undefined, listCleared: n, loop: loop ? { iteration: loop.iteration, active: loop.active } : undefined });
|
|
4225
|
+
if (live) {
|
|
4226
|
+
archiveCurrentGoal(ctx, "aborted", "user reset (/glla reset)");
|
|
4227
|
+
ctx.abort();
|
|
4228
|
+
} else if (g) {
|
|
4229
|
+
state = { ...state, goal: null };
|
|
4230
|
+
}
|
|
4231
|
+
if (n > 0) {
|
|
4232
|
+
state = { ...state, list: [] };
|
|
4233
|
+
appendLedger(ctx.cwd, "list_cleared", { via: "glla_reset" });
|
|
4234
|
+
}
|
|
4235
|
+
if (loop) {
|
|
4236
|
+
clearLoopTimer();
|
|
4237
|
+
state.loop = undefined;
|
|
4238
|
+
await finishLoopGit(ctx, loop);
|
|
4239
|
+
appendLedger(ctx.cwd, "loop_stopped", { reason: "user reset (/glla reset)", iterations: loop.iteration, best: loop.bestValue });
|
|
4240
|
+
}
|
|
4241
|
+
persistState(ctx);
|
|
4242
|
+
ctx.ui.notify(`glla reset done: ${parts.join(" · ")}. Clean slate.`, "info");
|
|
4243
|
+
notifyExternal(ctx, "glla state reset by user — clean slate.");
|
|
4244
|
+
}
|
|
4245
|
+
|
|
4185
4246
|
function cmdAudits(args: string, ctx: ExtensionContext): void {
|
|
4186
4247
|
const full = /\bfull\b/.test(args);
|
|
4187
4248
|
const all = /\b(?:all|global|log)\b/.test(args);
|
|
@@ -4239,6 +4300,11 @@ async function cmdSettings(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
4239
4300
|
cmdLog(trimmed.slice("log".length).trim(), ctx);
|
|
4240
4301
|
return;
|
|
4241
4302
|
}
|
|
4303
|
+
// v0.28.31: /glla reset — one-shot clean slate for leftover-laden projects.
|
|
4304
|
+
if (/^reset\b/.test(trimmed)) {
|
|
4305
|
+
await cmdGllaReset(ctx);
|
|
4306
|
+
return;
|
|
4307
|
+
}
|
|
4242
4308
|
if (/^reviewer\b/.test(trimmed)) {
|
|
4243
4309
|
await cmdReviewerSettings(ctx);
|
|
4244
4310
|
return;
|
|
@@ -4630,6 +4696,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
4630
4696
|
["decisionpopup=", "on|off: decision pauses pop the select() picker (default on; the widget card always lists the options, /goal decide reopens the picker)"],
|
|
4631
4697
|
["auditcap=", "N: pause goal after N consecutive auditor disapprovals (default 5, 0 = unlimited)"],
|
|
4632
4698
|
["log", "event-trail tail: /glla log [N] — who created/resumed/paused what, from where (v0.28.28)"],
|
|
4699
|
+
["reset", "wipe live glla state (goal archived, list cleared, loop stopped) — one-shot cleanup for leftover-laden projects"],
|
|
4633
4700
|
["auditfeedbackchars=", "cap on executor-visible disapproval report chars (0 = full report, the default)"],
|
|
4634
4701
|
["aggressivemode=", "on: keep-going defaults — autoResume, cap 10, stuck 10, wedge off, quota auto-retry, cap→TODOs"],
|
|
4635
4702
|
["quotaretryminutes=", "N: minutes before auto-retrying a quota-exhausted auditor (default 60)"],
|
|
@@ -5057,7 +5124,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
5057
5124
|
pauseReason: `stalled: ${HEARTBEAT_MAX_NUDGES} consecutive unproductive turns (no tools, short or repetitive)`,
|
|
5058
5125
|
pauseSuggestedAction: "Inspect the goal — /goal resume to retry, /goal tweak to narrow it, /goal cancel to abort.",
|
|
5059
5126
|
}, ctx);
|
|
5060
|
-
ctx.ui.notify(
|
|
5127
|
+
ctx.ui.notify(`${goalNoun()} paused: stalled (${HEARTBEAT_MAX_NUDGES} unproductive turns).`, "warning");
|
|
5061
5128
|
maybeDecisionPopup(ctx);
|
|
5062
5129
|
notifyExternal(ctx, "Goal paused: stalled (no tool calls).");
|
|
5063
5130
|
return;
|
|
@@ -5106,7 +5173,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
5106
5173
|
pauseReason: `token limit exceeded (${used.toLocaleString()} > ${limit.toLocaleString()})`,
|
|
5107
5174
|
pauseSuggestedAction: "/glla tokenlimit=<n> to raise the cap (or 0 to disable), then /goal resume",
|
|
5108
5175
|
}, ctx);
|
|
5109
|
-
ctx.ui.notify(
|
|
5176
|
+
ctx.ui.notify(`${goalNoun()} paused: token limit exceeded (${used.toLocaleString()} > ${limit.toLocaleString()}). /glla tokenlimit=<n> to raise, 0 to disable.`, "warning");
|
|
5110
5177
|
notifyExternal(ctx, `Goal paused: token limit exceeded (${used} > ${limit}).`);
|
|
5111
5178
|
return;
|
|
5112
5179
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.31",
|
|
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",
|