pi-goal-list-loop-audit 0.38.26 → 0.38.28
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/CHANGELOG.md +12 -0
- package/docs/INDEX.md +2 -2
- package/extensions/goal-loop-display.ts +27 -3
- package/extensions/goal-loop.ts +38 -1
- package/extensions/loops/goal-activation.ts +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.38.28 — close redundant provenance rows in the active goal card (2026-09-08)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- The active card no longer shows a duplicate `handled turn` row when it is the same model as the primary model. When provenance is the final detail block, its last row now closes with `└─` instead of a dangling `│`/`├─`, so the card no longer implies missing rows. Failover-handled turns remain visible. Added focused regression coverage; `tsc` and the focused display suite pass.
|
|
7
|
+
|
|
8
|
+
## 0.38.27 — selective port of PRs #45/#46: /loop pause + widget subtask count (2026-09-08)
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `/loop pause` soft-hold (ported from Bjynt's PR #46): parallel to `/goal pause` and `/glla pause` — clears the tick, holds iteration/best/history verbatim with `stopReason: "paused by user (/loop pause)"`, ledger `loop_paused`, no `finishLoopGit`, no queue advance; `/loop resume` picks it up via the extended `RESUMABLE_STOP`. Pinned by `tests/loop-pause.test.ts` (3 tests).
|
|
12
|
+
- Widget task count: a closed parent covers its subtasks (ported from Bjynt's PR #45 — field symptom 6 real tasks displayed "2/24"). Pinned (7/12 + 1/4 cases).
|
|
13
|
+
- Held with recorded rationale (`audit/PR-45-46-DISPOSITION-2026-09-08.md`): `auditTasks` per-task auditor (token-cost surface needs dedicated review), `bypassTriggered` abort shortening (round-trip untested + v0.38.24 abort-latch interaction unverified); dropped the malformed "best solution" auditor line (taste-judge scope creep). Full gate 1990 pass / 0 fail.
|
|
14
|
+
|
|
3
15
|
## 0.38.26 — approval-render store: spillway cap keeps undelivered renders (2026-09-08)
|
|
4
16
|
|
|
5
17
|
### Fixed
|
package/docs/INDEX.md
CHANGED
|
@@ -18,7 +18,7 @@ For shipped docs, the relevant entry points are:
|
|
|
18
18
|
failback; v0.35.9 hardened cross-version npm tarball checks; v0.35.10
|
|
19
19
|
handles multi-entry npm dry-run reports; v0.35.11 accepts both npm report
|
|
20
20
|
shapes; v0.35.12 supports npm 12's keyed pack reports; v0.35.13 fixes stale-API recovery loops.
|
|
21
|
-
v0.35.14–v0.38.
|
|
21
|
+
v0.35.14–v0.38.28 continue through the supervisor freeze (`/glla pause`),
|
|
22
22
|
load hold, auditor picker parity, Windows launch fix, zombie-watchdog
|
|
23
23
|
subagent carve-out, due-wait backstop, the `/glla agents` visibility panel,
|
|
24
24
|
durable state-root selection, blank-until-resume auditor context, frozen
|
|
@@ -28,7 +28,7 @@ For shipped docs, the relevant entry points are:
|
|
|
28
28
|
packed-artifact release verification, and the 2026-09-07 display/lifecycle/
|
|
29
29
|
settings audit pass (abort-latch send guards, ownership compare-and-swap,
|
|
30
30
|
auditor inherit/clear parity) and the v0.38.25 post-objective summary
|
|
31
|
-
(canonical approval render, persist + replay, audit-goal counts line) — see CHANGELOG.md for the full trail.
|
|
31
|
+
(canonical approval render, persist + replay, audit-goal counts line), the v0.38.27 selective port of PRs #45/#46 (`/loop pause` soft-hold, widget subtask count), and the v0.38.28 provenance-row closure fix — see CHANGELOG.md for the full trail.
|
|
32
32
|
- `../README.md` — what the plugin is, install, quickstart, and the
|
|
33
33
|
architectural guarantee (drafting + confirm + detached auditor).
|
|
34
34
|
- `../INSTALL.md` — source install / local development setup; the recommended
|
|
@@ -294,7 +294,13 @@ function modelProvenanceLines(provenance: ModelProvenanceDisplay | undefined, wi
|
|
|
294
294
|
const skipped = uniqueModelRefs(provenance.skippedForbiddenRefs);
|
|
295
295
|
if (skipped.length > 0) lines.push(`skipped forbidden: ${truncate(skipped.join(", "), budget)}`);
|
|
296
296
|
const handledTurn = typeof provenance.handledTurn === "string" ? provenance.handledTurn.trim() : "";
|
|
297
|
-
|
|
297
|
+
// A normal turn is handled by the configured primary model. Repeating the
|
|
298
|
+
// same ref immediately below it adds no information and, when it is the
|
|
299
|
+
// last row, leaves a misleading continuation glyph in the card. Keep the
|
|
300
|
+
// row only when a recovery/failover actually handled the turn.
|
|
301
|
+
if (handledTurn && handledTurn.toLowerCase() !== primary.toLowerCase()) {
|
|
302
|
+
lines.push(`handled turn: ${truncate(handledTurn, budget)}`);
|
|
303
|
+
}
|
|
298
304
|
const handledAudit = typeof provenance.handledAudit === "string" ? provenance.handledAudit.trim() : "";
|
|
299
305
|
if (handledAudit) {
|
|
300
306
|
const source = provenance.handledAuditSource?.trim() ? modelSourceLabel(provenance.handledAuditSource) : "";
|
|
@@ -1273,8 +1279,15 @@ function countDone(g: Goal): number {
|
|
|
1273
1279
|
let n = 0;
|
|
1274
1280
|
const walk = (ts: Array<{ status: string; subtasks?: any[] }>) => {
|
|
1275
1281
|
for (const t of ts) {
|
|
1276
|
-
if (t.status === "complete")
|
|
1277
|
-
|
|
1282
|
+
if (t.status === "complete") {
|
|
1283
|
+
// Ported from Bjynt's PR #45: a closed parent covers its subtasks
|
|
1284
|
+
// (field: 2 closed parents with pending subtasks displayed "2/24"
|
|
1285
|
+
// for 6 real tasks). Mid-flight parents still count done subtasks
|
|
1286
|
+
// independently via the walk below.
|
|
1287
|
+
n += 1 + (t.subtasks?.length ?? 0);
|
|
1288
|
+
} else if (t.subtasks) {
|
|
1289
|
+
walk(t.subtasks);
|
|
1290
|
+
}
|
|
1278
1291
|
}
|
|
1279
1292
|
};
|
|
1280
1293
|
walk(g.taskList?.tasks ?? []);
|
|
@@ -1573,6 +1586,7 @@ function goalLines(g: Goal, state: State, audit: AuditDisplayProgress | null | u
|
|
|
1573
1586
|
// particular, never replace a configured forbidden ref with "none" — the
|
|
1574
1587
|
// skipped line explains why it did not handle the turn.
|
|
1575
1588
|
const provenance = modelProvenanceLines(extras?.modelProvenance, width);
|
|
1589
|
+
const provenanceStart = lines.length;
|
|
1576
1590
|
provenance.forEach((line, i) => {
|
|
1577
1591
|
lines.push(`${i === 0 ? "├─" : "│ "} ${paint(theme, "dim", line)}`);
|
|
1578
1592
|
});
|
|
@@ -1897,6 +1911,16 @@ function goalLines(g: Goal, state: State, audit: AuditDisplayProgress | null | u
|
|
|
1897
1911
|
// `/goal status` / `/glla` command hints were extension meta, not task
|
|
1898
1912
|
// information — dropped. No queue, no footer at all.
|
|
1899
1913
|
if (queue > 0) lines.push(`└─ ${paint(theme, "dim", `${queue} queued`)}`);
|
|
1914
|
+
// v0.38.28: provenance rows can be the entire detail block when there is
|
|
1915
|
+
// no recent action, pending task, or queue footer. Close that block with a
|
|
1916
|
+
// terminator instead of leaving `├─`/`│` suggesting missing rows.
|
|
1917
|
+
const provenanceEnd = provenanceStart + provenance.length;
|
|
1918
|
+
if (provenance.length > 0 && provenanceEnd === lines.length) {
|
|
1919
|
+
const last = lines[provenanceEnd - 1]!;
|
|
1920
|
+
if (last.startsWith("├─ ") || last.startsWith("│ ")) {
|
|
1921
|
+
lines[provenanceEnd - 1] = `└─ ${last.slice(3)}`;
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1900
1924
|
return lines;
|
|
1901
1925
|
}
|
|
1902
1926
|
|
package/extensions/goal-loop.ts
CHANGED
|
@@ -1032,7 +1032,11 @@ async function cmdLoop(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
1032
1032
|
// predicate it lands in never matched the prefix, so /loop resume
|
|
1033
1033
|
// answered "No held loop to resume" and the preserved iteration,
|
|
1034
1034
|
// best value, and history were unreachable without re-drafting.
|
|
1035
|
-
!!r?.startsWith("stopped: automatic zero-stream abort")
|
|
1035
|
+
!!r?.startsWith("stopped: automatic zero-stream abort") ||
|
|
1036
|
+
// v0.38.27 (ported from Bjynt's PR #46): /loop pause is a soft-hold
|
|
1037
|
+
// parallel to /goal pause. The loop stays resumable; finishLoopGit
|
|
1038
|
+
// was skipped, so resume picks up iteration/best/history verbatim.
|
|
1039
|
+
!!r?.startsWith("paused by user (/loop pause)");
|
|
1036
1040
|
if (stored && !stored.active && RESUMABLE_STOP(stored.stopReason)) {
|
|
1037
1041
|
// Branch-mode stop returns HEAD to originalBranch. Refuse a resume from
|
|
1038
1042
|
// there rather than letting the next tick commit loop work to the
|
|
@@ -1255,6 +1259,39 @@ async function cmdLoop(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
1255
1259
|
return;
|
|
1256
1260
|
}
|
|
1257
1261
|
|
|
1262
|
+
// v0.38.27 (ported from Bjynt's PR #46): soft-hold, parallel to /goal
|
|
1263
|
+
// pause and /glla pause. The loop stops firing iterations but stays in
|
|
1264
|
+
// a resumable held state — NO finishLoopGit, NO hard-stop ledger, NO
|
|
1265
|
+
// list-queue advance. /loop resume picks it up via RESUMABLE_STOP with
|
|
1266
|
+
// iteration, best value, and history preserved verbatim.
|
|
1267
|
+
if (sub === "pause") {
|
|
1268
|
+
if (!state.loop) {
|
|
1269
|
+
ctx.ui.notify("No loop to pause.", "info");
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1272
|
+
if (!state.loop.active) {
|
|
1273
|
+
ctx.ui.notify(`Loop is not active (${state.loop.stopReason ?? "held"}). Use /loop resume to continue, or /loop status to inspect.`, "info");
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
clearLoopTimer();
|
|
1277
|
+
clearToolActivityState();
|
|
1278
|
+
if (state.mainModelRecovery?.kind === "loop") {
|
|
1279
|
+
clearMainModelRecoveryTimer();
|
|
1280
|
+
state.mainModelRecovery = undefined;
|
|
1281
|
+
flags.mainModelAbortForRecovery = false;
|
|
1282
|
+
flags.continuationDispatchStoodDown = false;
|
|
1283
|
+
}
|
|
1284
|
+
state.loop = { ...state.loop, active: false, stopReason: "paused by user (/loop pause)" };
|
|
1285
|
+
persistState(ctx);
|
|
1286
|
+
appendLedger(ctx.cwd, "loop_paused", { reason: "user", iterations: state.loop.iteration, best: state.loop.bestValue });
|
|
1287
|
+
ctx.ui.notify(
|
|
1288
|
+
`Loop paused after ${state.loop.iteration} iterations. Best: ${state.loop.bestValue ?? "n/a"}.\nUse /loop resume to continue.`,
|
|
1289
|
+
"info",
|
|
1290
|
+
);
|
|
1291
|
+
notifyExternal(ctx, `Loop paused by user after ${state.loop.iteration} iterations (best: ${state.loop.bestValue ?? "n/a"}). /loop resume to continue.`);
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1258
1295
|
// v0.25.1: a CLEAN end — "completed: <reason>", distinct from
|
|
1259
1296
|
// stuck/plateau/stopped-by-user. Additive: /loop stop is untouched.
|
|
1260
1297
|
if (sub === "finish") {
|
|
@@ -867,6 +867,7 @@ export function registerGoalRuntime(pi: ExtensionAPI): void {
|
|
|
867
867
|
["polish", "alias of /loop refine"],
|
|
868
868
|
["stop", "end the loop (keeps the best state)"],
|
|
869
869
|
["cancel", "alias of /loop stop — end the loop"],
|
|
870
|
+
["pause", "hold the active loop (soft-hold, resumable via /loop resume)"],
|
|
870
871
|
["finish", "end the loop cleanly: /loop finish [reason] → stopReason 'completed: <reason>'"],
|
|
871
872
|
]),
|
|
872
873
|
handler: (args: string, ctx: ExtensionContext) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.38.
|
|
3
|
+
"version": "0.38.28",
|
|
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. A detached extension-less auditor process re-verifies every completion with raw evidence without holding the main pi turn; confirmed drafts, decision pauses and consent gates keep you in charge.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"author": "dracon",
|