pi-goal-list-loop-audit 0.28.20 → 0.28.21

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 CHANGED
@@ -203,7 +203,7 @@ No external watchdog plugin needed.
203
203
  /glla tokenlimit=10000000 # per-goal token budget (default: off) → GLOBAL
204
204
  /glla tokenlimit=0 # explicitly no cap (the default)
205
205
  /glla wedgealert=30 # hung-command alert minutes (default: 30, 0 = off)
206
- /glla autoresume=on # auto-resume goals/loops on session LOAD too (default: hold on load, auto-resume on reload/fork; off: never)
206
+ /glla autoresume=on # auto-resume goals/loops on ANY session start (default: load HELD, never auto-start — explicit /goal resume, /list resume, or /loop; off: never)
207
207
  /glla auditcap=5 # pause the goal after N consecutive auditor disapprovals (default 5, 0 = unlimited)
208
208
  /glla aggressivemode=on # keep-going defaults: autoResume, cap 10, stuck 10, wedge off, quota auto-retry, cap→TODOs
209
209
  /glla quotaretryminutes=60 # minutes before auto-retrying a quota-exhausted auditor
@@ -728,21 +728,21 @@ export function cloneGoal(goal: Goal): Goal {
728
728
  * setting for unattended restarts). One mechanical predicate; no heuristics.
729
729
  */
730
730
  export function shouldAutoResumeOnSessionStart(reason: string | undefined, autoResume: boolean | undefined): boolean {
731
- // v0.26.9 tri-state:
732
- // true → auto-resume on EVERY session start (unattended rigs).
731
+ // v0.28.21: the DEFAULT flipped to hold-everything (user directive:
732
+ // "load it on session load but not auto start it"). Tri-state:
733
+ // true → auto-resume on EVERY session start (unattended rigs;
734
+ // /glla autoresume=on — this is the ONLY auto-resume path).
733
735
  // false → never auto-resume; always hold for an explicit resume.
734
- // undefined → DEFAULT: a human LOADING a session ("startup"/"new"/
735
- // "resume", or old pi reporting no reason) must not trigger
736
- // work — show the held popup, they resume explicitly.
737
- // In-session MACHINERY ("reload"/"fork") auto-resumes so an
738
- // extension reload or session fork never strands work.
736
+ // undefined → DEFAULT: never auto-resume either — whatever the reason
737
+ // ("startup"/"new"/"resume"/"reload"/"fork"/none), the
738
+ // item is LOADED (visible, state intact) but HELD until an
739
+ // explicit /goal resume, /list resume, or /loop.
739
740
  // Mid-session continuation (agent_end chains, heartbeat refires,
740
741
  // post-compaction, list/loop transitions) is not gated here at all — it
741
742
  // auto-continues forever unless a super-stuck brake (stall escalation,
742
743
  // stale-api terminal, pending-latch watchdog) stops it loudly.
743
- if (autoResume === true) return true;
744
- if (autoResume === false) return false;
745
- return reason === "reload" || reason === "fork";
744
+ void reason; // retained for the signature; no reason auto-resumes by default anymore
745
+ return autoResume === true;
746
746
  }
747
747
 
748
748
  /**
@@ -1194,9 +1194,9 @@ async function cmdSet(args: string, ctx: ExtensionContext, skipDraft = false): P
1194
1194
  consecutiveNoToolIterations = 0;
1195
1195
  if (staleEntry) {
1196
1196
  // v0.28.1 (S3): the goal is persisted — mark the interrupt so the next
1197
- // fresh session auto-resumes, and tell the truth instead of "starting now".
1197
+ // fresh session LOADS it (held by default since v0.28.21), and tell the truth instead of "starting now".
1198
1198
  updateGoal({ interruptedAt: nowIso(), interruptedReason: "created in a stale session" }, ctx);
1199
- ctx.ui.notify(`Goal saved: ${shortObj(goal.objective)} — safe in .pi-glla/, but this stale process can't send continuations. Restart pi and it auto-resumes. (id: ${goal.id})`, "warning");
1199
+ ctx.ui.notify(`Goal saved: ${shortObj(goal.objective)} — safe in .pi-glla/, but this stale process can't send continuations. Restart pi, then /goal resume (v0.28.21: session loads no longer auto-start by default). (id: ${goal.id})`, "warning");
1200
1200
  return;
1201
1201
  }
1202
1202
  ctx.ui.notify(`Goal started: ${shortObj(goal.objective)} — the auditor will verify on completion. (id: ${goal.id})`, "info");
@@ -1239,6 +1239,13 @@ async function cmdPause(ctx: ExtensionContext): Promise<void> {
1239
1239
 
1240
1240
  async function cmdResume(ctx: ExtensionContext): Promise<void> {
1241
1241
  if (!state.goal || state.goal.status !== "paused") return;
1242
+ // v0.28.21: one-active-thing — the LAST unguarded activation path. A
1243
+ // paused goal/list-item must not resume over a live loop (covers
1244
+ // /goal resume AND /list resume, which routes here).
1245
+ if (isLoopActive()) {
1246
+ ctx.ui.notify("A loop is active — one active thing at a time. /loop stop it first, then resume the goal.", "warning");
1247
+ return;
1248
+ }
1242
1249
  // v0.28.1 (S1/S3): resuming in a stale session used to flip status to
1243
1250
  // active, claim "Resumed goal", then re-pause on the stale send failure
1244
1251
  // (or zombie — S1). Now: persist the resume (the next fresh session
@@ -4460,12 +4467,13 @@ export default function (pi: ExtensionAPI): void {
4460
4467
  );
4461
4468
  }
4462
4469
  } else if (state.goal && state.goal.status === "active" && state.goal.autoContinue) {
4463
- // v0.28.3 (S2 completed): an infra interrupt outranks the DEFAULT
4464
- // hold — the goal never chose to stop; pi killed its handle. With
4465
- // autoresume unset, an interrupted goal auto-resumes even on a human
4466
- // session load; explicit /glla autoresume=off still holds.
4467
4470
  const wasInterrupted = !!state.goal.interruptedAt;
4468
- if (autoResume || (wasInterrupted && autoResumeSetting !== false)) {
4471
+ // v0.28.21: the 0.28.3 interrupted-goal exemption is SUPERSEDED —
4472
+ // the default is now hold-everything on session load (user directive:
4473
+ // "load it but not auto start it"). Interrupted goals hold like
4474
+ // everything else; autoresume=on (unattended rigs) still auto-resumes
4475
+ // them, and the marker is cleared only on that promised auto-resume.
4476
+ if (autoResume) {
4469
4477
  // v0.28.1 (S2): clear the stale-handle interrupt marker — this IS
4470
4478
  // the auto-resume the marker promised.
4471
4479
  if (wasInterrupted) updateGoal({ interruptedAt: undefined, interruptedReason: undefined }, ctx);
@@ -4506,6 +4514,22 @@ export default function (pi: ExtensionAPI): void {
4506
4514
  ctx.ui.notify(`List has ${listQueue().length} item(s) waiting — /list next to activate the head.`, "info");
4507
4515
  }
4508
4516
  }
4517
+ // v0.28.21: enforce one-active-thing at the restore boundary for DIRTY
4518
+ // legacy states — pre-guard versions could persist an active goal AND
4519
+ // an active/held loop; the chain above handles the loop first, and the
4520
+ // goal would otherwise stay active and fire on agent_end. Pause it:
4521
+ // at most one thing owns the active slot, and nothing auto-starts.
4522
+ if (state.loop && state.goal && state.goal.status === "active") {
4523
+ updateGoal({
4524
+ status: "paused",
4525
+ pauseReason: "held on session load — the loop owns the active slot (one active thing at a time)",
4526
+ pauseSuggestedAction: "/loop to work the loop, or /loop stop then /goal resume to work the goal",
4527
+ }, ctx);
4528
+ ctx.ui.notify(
4529
+ `Goal [${state.goal.id}] held — a loop also exists; one active thing at a time. /loop to resume the loop, or /loop stop then /goal resume.`,
4530
+ "info",
4531
+ );
4532
+ }
4509
4533
  // Always paint on session load (v0.22.1): the branches above only reach
4510
4534
  // refreshUI via persistState, so a goal that was ALREADY paused (or any
4511
4535
  // state that doesn't mutate on load) rendered nothing — "can't tell if
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goal-list-loop-audit",
3
- "version": "0.28.20",
3
+ "version": "0.28.21",
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",