pi-goal-list-loop-audit 0.38.95 → 0.38.97
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 +8 -0
- package/docs/INDEX.md +1 -1
- package/extensions/goal-commands.ts +10 -0
- package/extensions/goal-loop.ts +8 -0
- package/extensions/loops/goal-tools.ts +22 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.38.97 — pause_goal redirect: park-and-continue for user interruptions (2026-09-23)
|
|
4
|
+
|
|
5
|
+
- Field: a mid-goal redirect ("can we get to this first") parked via pause_goal, whose abort + "do NOT continue working" stranded the new task until the user nudged. New optional `redirect` param parks the goal WITHOUT ending the turn and orders the redirect worked immediately, goal resumed after; redirect parks ledger distinctly as `pause_goal_redirect`. Plain pauses still abort (audit/PAUSE-REDIRECT-2026-09-23.md).
|
|
6
|
+
|
|
7
|
+
## 0.38.96 — /glla resume + /loop resume release the load hold before probing (2026-09-23)
|
|
8
|
+
|
|
9
|
+
- Field: a deterministic-400 manual hold cold-loaded (load hold engaged), then `/glla resume` consumed the manual hold and the goal stayed parked — the fired recovery probe died silently on the `supervisorPaused` gate, which includes `loadHoldAt`. No probe, no timer, stale resume text. `/glla resume` and `/loop resume` now release the cold-load hold at entry like `/goal resume` and agent-resume already do (audit/GLLA-RESUME-LOAD-HOLD-2026-09-23.md). Workaround on 0.38.95: run `/goal resume`.
|
|
10
|
+
|
|
3
11
|
## 0.38.95 — Stop the pause cycles: image-count clamp, ledger dedupe (2026-09-23)
|
|
4
12
|
|
|
5
13
|
- The payload guard now clamps image blocks per request (default 4, the observed provider limit) as well as bytes — small screenshots fit the byte budget but 400'd on count (field 2026-09-21: `Image count 12 exceeds limit 4`). Oldest-first, keep-recent floor wins on conflict; eviction entries carry the remaining count (audit/PAUSES-2026-09-22.md).
|
package/docs/INDEX.md
CHANGED
|
@@ -16,7 +16,7 @@ Policy contracts and recent changes live in the `audit/` directory of the
|
|
|
16
16
|
failback; v0.35.9 hardened cross-version npm tarball checks; v0.35.10
|
|
17
17
|
handles multi-entry npm dry-run reports; v0.35.11 accepts both npm report
|
|
18
18
|
shapes; v0.35.12 supports npm 12's keyed pack reports; v0.35.13 fixes stale-API recovery loops.
|
|
19
|
-
v0.35.14–v0.38.
|
|
19
|
+
v0.35.14–v0.38.97 continue through the supervisor freeze (`/glla pause`),
|
|
20
20
|
load hold, auditor picker parity, Windows launch fix, zombie-watchdog
|
|
21
21
|
subagent carve-out, due-wait backstop, the `/glla agents` visibility panel,
|
|
22
22
|
durable state-root selection, blank-until-resume auditor context, frozen
|
|
@@ -2481,6 +2481,16 @@ async function cmdGllaResume(ctx: ExtensionContext): Promise<void> {
|
|
|
2481
2481
|
appendLedger(ctx.cwd, "supervisor_resume", { frozenMs });
|
|
2482
2482
|
ctx.ui.notify(`Supervisor RESUMED after ${fmtElapsed(frozenMs)} — heartbeat re-arms, recovery probes, auto-resume, continuation dispatch, and auditor quiet notifies are live again.`, "info");
|
|
2483
2483
|
}
|
|
2484
|
+
// v0.38.96 (field 2026-09-23, dracon-utilities): /glla resume carries the
|
|
2485
|
+
// same consent semantics as /goal resume, so it must release the cold-load
|
|
2486
|
+
// hold too — otherwise manuallyResumeMainModelRecovery consumes the manual
|
|
2487
|
+
// hold and its probe dies silently on the supervisorPaused gate (which
|
|
2488
|
+
// includes loadHoldAt): no probe, no timer, goal still parked.
|
|
2489
|
+
if (clearLoadHold(state)) {
|
|
2490
|
+
persistState(ctx);
|
|
2491
|
+
appendLedger(ctx.cwd, "load_hold_released", { via: "glla-resume" });
|
|
2492
|
+
ctx.ui.notify("Load hold released — automation is live again.", "info");
|
|
2493
|
+
}
|
|
2484
2494
|
if (manuallyResumeMainModelRecovery(ctx)) return;
|
|
2485
2495
|
if (state.mainModelRecovery?.retryAt || state.mainModelRecovery?.pendingModelSwitch) {
|
|
2486
2496
|
clearMainModelRecoveryTimer();
|
package/extensions/goal-loop.ts
CHANGED
|
@@ -1015,6 +1015,14 @@ async function cmdLoop(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
1015
1015
|
|
|
1016
1016
|
if (!sub || sub === "resume") {
|
|
1017
1017
|
releaseInitialSessionLoadBarrier();
|
|
1018
|
+
// v0.38.96 (field 2026-09-23): same release the held-loop path does
|
|
1019
|
+
// below, but at entry — the recovery branches return before it, and a
|
|
1020
|
+
// manual-resume probe fired under a load hold dies silently on the
|
|
1021
|
+
// supervisorPaused gate (hold consumed, loop still held, nothing armed).
|
|
1022
|
+
if (clearLoadHold(state)) {
|
|
1023
|
+
persistState(ctx);
|
|
1024
|
+
appendLedger(ctx.cwd, "load_hold_released", { via: "loop-resume" });
|
|
1025
|
+
}
|
|
1018
1026
|
if (state.mainModelRecovery?.manualResumeRequired && state.mainModelRecovery.kind === "loop") {
|
|
1019
1027
|
manuallyResumeMainModelRecovery(ctx);
|
|
1020
1028
|
return;
|
|
@@ -2276,7 +2276,7 @@ function registerAgentTools(pi: any): void {
|
|
|
2276
2276
|
pi.registerTool(defineTool({
|
|
2277
2277
|
name: "pause_goal",
|
|
2278
2278
|
label: "Pause goal",
|
|
2279
|
-
description: "Pause the active goal with a reason and suggested action. Use when blocked on user input or unable to make progress. Pausing ABORTS the current turn immediately — after this call, stop; never keep working. When the user must CHOOSE between options, pass kind=\"decision\" with the options list (recommended = 1-based index of the best one) — decision pauses render as a prominent DECISION NEEDED card and pop a picker for the user. Time-gated waits (retry at a specific time) use kind=\"wait\" with resumeAt (ISO). Operational failures use kind=\"error\". Pauses that only wait on a running background subagent — its native completion wakes the goal, no manual action exists — use kind=\"standby\" so the card waits instead of demanding action. VOCABULARY (v0.28.24): decision options and reasons must reference REAL commands only — /goal resume, /goal cancel, /goal tweak \"<new text>\", /list remove N, /list next, /list resume, /loop stop, /loop resume. These all act on the ACTIVE goal/item: there is NO /goal drop and NO command takes a goal id. Never show goal ids to the user — name the thing ('the active goal', 'list item \"<short name>\"'); ids are internal plumbing the user cannot act on.",
|
|
2279
|
+
description: "Pause the active goal with a reason and suggested action. Use when blocked on user input or unable to make progress. Pausing ABORTS the current turn immediately — after this call, stop; never keep working. When the user interrupts with a NEW task ('do X first'), pass redirect=\"<their request>\" instead: the goal parks but the turn CONTINUES so you work X immediately — a plain pause strands the redirect until the user nudges. Never use redirect to dodge a real blocker, decision, or wait. When the user must CHOOSE between options, pass kind=\"decision\" with the options list (recommended = 1-based index of the best one) — decision pauses render as a prominent DECISION NEEDED card and pop a picker for the user. Time-gated waits (retry at a specific time) use kind=\"wait\" with resumeAt (ISO). Operational failures use kind=\"error\". Pauses that only wait on a running background subagent — its native completion wakes the goal, no manual action exists — use kind=\"standby\" so the card waits instead of demanding action. VOCABULARY (v0.28.24): decision options and reasons must reference REAL commands only — /goal resume, /goal cancel, /goal tweak \"<new text>\", /list remove N, /list next, /list resume, /loop stop, /loop resume. These all act on the ACTIVE goal/item: there is NO /goal drop and NO command takes a goal id. Never show goal ids to the user — name the thing ('the active goal', 'list item \"<short name>\"'); ids are internal plumbing the user cannot act on.",
|
|
2280
2280
|
parameters: Type.Object({
|
|
2281
2281
|
reason: Type.String({ description: "Why the work is paused" }),
|
|
2282
2282
|
suggestedAction: Type.Optional(Type.String({ description: "What the user should do next" })),
|
|
@@ -2284,13 +2284,14 @@ function registerAgentTools(pi: any): void {
|
|
|
2284
2284
|
options: Type.Optional(Type.Array(Type.String(), { description: "For kind=decision: the options the user picks between (one line each)" })),
|
|
2285
2285
|
recommended: Type.Optional(Type.Number({ description: "For kind=decision: 1-based index of the recommended option" })),
|
|
2286
2286
|
resumeAt: Type.Optional(Type.String({ description: "For kind=wait: ISO time the pause lifts (countdown is shown)" })),
|
|
2287
|
+
redirect: Type.Optional(Type.String({ description: "User redirect to work IMMEDIATELY in this same turn (quote or summarize the interrupting request). Parks the goal WITHOUT ending the turn; the result orders the redirect worked now and the goal resumed after. Only for genuine user redirects." })),
|
|
2287
2288
|
}),
|
|
2288
2289
|
async execute(_id, params, _signal, _onUpdate, execCtx) {
|
|
2289
2290
|
const foreign1 = foreignToolGuard(execCtx);
|
|
2290
2291
|
if (foreign1) return { content: [{ type: "text", text: foreign1 }], details: {} };
|
|
2291
2292
|
const ctx = currentToolContext(execCtx);
|
|
2292
2293
|
if (!ctx) return staleToolResult();
|
|
2293
|
-
const p = params as { reason: string; suggestedAction?: string; kind?: "decision" | "error" | "wait" | "blocked" | "standby"; options?: string[]; recommended?: number; resumeAt?: string };
|
|
2294
|
+
const p = params as { reason: string; suggestedAction?: string; kind?: "decision" | "error" | "wait" | "blocked" | "standby"; options?: string[]; recommended?: number; resumeAt?: string; redirect?: string };
|
|
2294
2295
|
// v0.35.15: a model that passes options but forgets kind="decision"
|
|
2295
2296
|
// still gets the decision card — a non-empty options array IS the
|
|
2296
2297
|
// decision intent; silently dropping it left the user with no picker.
|
|
@@ -2540,13 +2541,31 @@ function registerAgentTools(pi: any): void {
|
|
|
2540
2541
|
// picker can own the screen. The impossible-drop advance is the one
|
|
2541
2542
|
// exception: the queue already moved to the next item and its
|
|
2542
2543
|
// continuation owns this turn — aborting would kill the hand-off.
|
|
2543
|
-
|
|
2544
|
+
// v0.38.97 (field 2026-09-23, dracon-platform): a user redirect is
|
|
2545
|
+
// park-and-CONTINUE, not park-and-stop. When redirect carries the
|
|
2546
|
+
// interrupting request, skip the abort so the turn survives and the
|
|
2547
|
+
// redirect runs NOW — aborting strands it until the user nudges.
|
|
2548
|
+
// Ledgered distinctly so redirect parks don't pollute abort
|
|
2549
|
+
// forensics. An impossible-drop still wins the result copy below.
|
|
2550
|
+
const redirect = (p.redirect ?? "").trim();
|
|
2551
|
+
if (!droppedImpossible && !redirect) {
|
|
2544
2552
|
try {
|
|
2545
2553
|
ctx.abort();
|
|
2546
2554
|
appendLedger(ctx.cwd, "pause_goal_aborted_turn", { goalId: state.goal?.id, kind: p.kind ?? "blocked" });
|
|
2547
2555
|
} catch (abortError) {
|
|
2548
2556
|
appendLedger(ctx.cwd, "pause_goal_abort_failed", { goalId: state.goal?.id, error: abortError instanceof Error ? abortError.message : String(abortError) });
|
|
2549
2557
|
}
|
|
2558
|
+
} else if (redirect && !droppedImpossible) {
|
|
2559
|
+
appendLedger(ctx.cwd, "pause_goal_redirect", { goalId: state.goal?.id, kind: p.kind ?? "blocked" });
|
|
2560
|
+
}
|
|
2561
|
+
if (redirect && !droppedImpossible) {
|
|
2562
|
+
return {
|
|
2563
|
+
content: [{
|
|
2564
|
+
type: "text",
|
|
2565
|
+
text: `Goal parked for a user redirect — do NOT work the goal. Work this NOW in the same turn, without ending the turn: ${redirect}. When it is done, ${activeGoalSurfaceCommand("resume")} the goal (or resume_goal) and continue.${waitClampNotice}`,
|
|
2566
|
+
}],
|
|
2567
|
+
details: {},
|
|
2568
|
+
};
|
|
2550
2569
|
}
|
|
2551
2570
|
return {
|
|
2552
2571
|
content: [{
|
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.97",
|
|
4
4
|
"description": "Mission control for long running pi work: interview drafted goals, an audited task queue, and metric or audit loops that run for hours. Every completion is rechecked by a detached auditor with raw evidence, while Confirm drafts, decision pauses, and consent gates keep you in charge.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"author": "dracon",
|