pi-goal-list-loop-audit 0.29.4 → 0.29.5

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.
@@ -152,6 +152,21 @@ export function loadSettings(cwd: string): Settings {
152
152
  ) as unknown as Settings;
153
153
  }
154
154
 
155
+ /**
156
+ * v0.29.5: autoResume is GLOBAL-only (user directive 2026-07-30: "we are
157
+ * not supporting project level setting for it now, just global"). Launch-
158
+ * time restore reads this, never the project file — a stale autoResume
159
+ * key in a project's settings.json is ignored (junk-runner field case: a
160
+ * project-local opt-in from the unattended-audit era kept auto-firing the
161
+ * list at every bare `pi` launch after the global default flipped off).
162
+ */
163
+ export function loadGlobalSettings(): Settings {
164
+ return mergeSettings(
165
+ DEFAULT_SETTINGS as unknown as Record<string, unknown>,
166
+ readSettingsFile(globalSettingsPath()) as Record<string, unknown>,
167
+ ) as unknown as Settings;
168
+ }
169
+
155
170
  /** Every provenance-tracked key (the /glla headless display + UI). */
156
171
  export const SETTINGS_KEYS: Array<keyof Settings> = [
157
172
  "auditorModel",
@@ -106,6 +106,7 @@ import {
106
106
  DEFAULT_SETTINGS,
107
107
  SETTINGS_KEYS,
108
108
  globalSettingsPath,
109
+ loadGlobalSettings,
109
110
  loadSettings,
110
111
  projectSettingsPath,
111
112
  saveSettings,
@@ -706,6 +707,10 @@ function heartbeatTick(): void {
706
707
  ctx.ui.notify(msg, "warning");
707
708
  notifyExternal(ctx, msg);
708
709
  }
710
+ // v0.29.5: user-abort stand-down — the chain stays DOWN until the
711
+ // user resumes. Without this guard the 60s heartbeat re-fired the
712
+ // continuation and defeated the 0.29.4 stand-down within a minute.
713
+ if (abortedStandDown) return;
709
714
  if (!fire) return;
710
715
  // v0.26.6: the 0.25.0 "recent ship (<5m)" suppression was REMOVED. It fed
711
716
  // lastShippedAtMs, which read the state-file MTIME — and the heartbeat's
@@ -747,6 +752,10 @@ let consecutiveErrorIterations = 0;
747
752
  // v0.28.5 (E8): user aborts are NOT provider errors — separate counter,
748
753
  // separate brake message, and no auto-resume (aborting is user intent).
749
754
  let consecutiveAbortIterations = 0;
755
+ // v0.29.5: set when a user abort stands the chain down (0.29.4) — the
756
+ // heartbeat refire + post-compaction refire must NOT resurrect it; only
757
+ // an explicit schedule (resume/activate/next turn) clears it.
758
+ let abortedStandDown = false;
750
759
  let consecutiveNoToolIterations = 0;
751
760
 
752
761
  // =================================================================
@@ -779,6 +788,7 @@ function freshCtx(): ExtensionContext | null {
779
788
  }
780
789
 
781
790
  function scheduleContinuation(ctx: ExtensionContext, force = false, delayMs?: number): void {
791
+ abortedStandDown = false; // v0.29.5: any explicit schedule ends the stand-down
782
792
  if (!isActionableGoal()) return;
783
793
  rememberCtx(ctx);
784
794
  const goalId = state.goal!.id;
@@ -1223,7 +1233,7 @@ function fireReviewer(
1223
1233
  manual: opts.manual,
1224
1234
  ledgerEntries,
1225
1235
  sources,
1226
- enqueueListItems: (objectives) => enqueueItems(ctx, objectives, "reviewer", { autoActivate: loadSettings(ctx.cwd).autoResume === true }),
1236
+ enqueueListItems: (objectives) => enqueueItems(ctx, objectives, "reviewer", { autoActivate: loadGlobalSettings().autoResume === true }),
1227
1237
  proposeGoal: (objective, reason) => {
1228
1238
  try {
1229
1239
  extensionApi?.sendUserMessage(
@@ -5060,7 +5070,7 @@ export default function (pi: ExtensionAPI): void {
5060
5070
  const c = freshCtx();
5061
5071
  if (!c) return;
5062
5072
  try {
5063
- if (c.isIdle() && !c.hasPendingMessages() && continuationTimer === null && loopTimer === null && isSupervising()) {
5073
+ if (c.isIdle() && !c.hasPendingMessages() && continuationTimer === null && loopTimer === null && isSupervising() && !abortedStandDown) {
5064
5074
  appendLedger(c.cwd, "compaction_refire", {});
5065
5075
  if (isLoopActive()) scheduleLoopTick(c);
5066
5076
  else scheduleContinuation(c, true);
@@ -5185,12 +5195,13 @@ export default function (pi: ExtensionAPI): void {
5185
5195
  // Restore gate (v0.26.9 tri-state): a human LOADING a session
5186
5196
  // ("startup"/"new"/"resume", or no reason) HOLDS — the popup shows what
5187
5197
  // is waiting and nothing starts until they resume explicitly. In-session
5188
- // machinery ("reload"/"fork") auto-resumes. /glla autoresume=on opts a
5189
- // project into auto-resume everywhere (unattended rigs); autoresume=off
5190
- // never auto-resumes. Once running, the chain auto-continues forever
5191
- // unless a super-stuck brake (stall escalation / stale-api / latch)
5192
- // stops it loudly.
5193
- const autoResumeSetting = resolveEffectiveAggressiveSettings(loadSettings(ctx.cwd)).autoResume;
5198
+ // machinery ("reload"/"fork") auto-resumes. /glla autoresume=on opts
5199
+ // into auto-resume everywhere (unattended rigs); autoresume=off never
5200
+ // auto-resumes. v0.29.5: the setting is GLOBAL-only — project-level
5201
+ // autoResume keys are ignored. Once running, the chain auto-continues
5202
+ // forever unless a super-stuck brake (stall escalation / stale-api /
5203
+ // latch) stops it loudly.
5204
+ const autoResumeSetting = resolveEffectiveAggressiveSettings(loadGlobalSettings()).autoResume;
5194
5205
  const autoResume = shouldAutoResumeOnSessionStart(event?.reason, autoResumeSetting);
5195
5206
  // v0.25.0 (contract item 6): aggressiveMode announces every auto-event.
5196
5207
  if (
@@ -5212,7 +5223,7 @@ export default function (pi: ExtensionAPI): void {
5212
5223
  state.loop = { ...l, active: false, stopReason: HELD_ON_RESTORE };
5213
5224
  persistState(ctx);
5214
5225
  ctx.ui.notify(
5215
- `Loop held on restore: ${l.target.slice(0, 60)} — /loop resume to continue, /glla autoresume=on to auto-resume on session load in this project.`,
5226
+ `Loop held on restore: ${l.target.slice(0, 60)} — /loop resume to continue, /glla autoresume=on to auto-resume on session load (global setting).`,
5216
5227
  "info",
5217
5228
  );
5218
5229
  }
@@ -5239,7 +5250,7 @@ export default function (pi: ExtensionAPI): void {
5239
5250
  // v0.22.7: name WHAT is held — a list head resumes through /list.
5240
5251
  const isListItem = state.goal.policy === "list";
5241
5252
  const resumeCmd = isListItem ? "/list resume" : "/goal resume";
5242
- const resumeHint = `${resumeCmd} to continue${queued > 0 ? ` (+${queued} waiting in the list)` : ""} · /glla autoresume=on to auto-resume in this project`;
5253
+ const resumeHint = `${resumeCmd} to continue${queued > 0 ? ` (+${queued} waiting in the list)` : ""} · /glla autoresume=on to auto-resume on load (global setting)`;
5243
5254
  updateGoal({
5244
5255
  status: "paused",
5245
5256
  pauseKind: "blocked",
@@ -5529,6 +5540,7 @@ export default function (pi: ExtensionAPI): void {
5529
5540
  // was answered by another turn under the user's hands ("it auto
5530
5541
  // triggered and I kept spamming esc on it" — pully, 2026-07-30).
5531
5542
  ctx.ui.notify(`${goalNoun()} standing down — turn aborted by user (not counted toward stalls). /goal resume to continue, /goal cancel to stop.`, "info");
5543
+ abortedStandDown = true; // v0.29.5: heartbeat/compaction refires must not resurrect the chain
5532
5544
  appendLedger(ctx.cwd, "abort_stand_down", { consecutiveAborts: consecutiveAbortIterations });
5533
5545
  return;
5534
5546
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goal-list-loop-audit",
3
- "version": "0.29.4",
3
+ "version": "0.29.5",
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",