pi-goal-list-loop-audit 0.26.9 → 0.27.0

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.
@@ -2852,66 +2852,93 @@ async function openSettingsUI(ctx: ExtensionContext): Promise<void> {
2852
2852
  const v = p.value === undefined ? fallback : String(p.value);
2853
2853
  return `${v} [${p.source}]`;
2854
2854
  };
2855
+ const settings = loadSettings(ctx.cwd);
2856
+ // v0.27.0: every option on ONE screen, grouped into sections, each row
2857
+ // carrying `label — value [provenance] — what it does` so the menu is
2858
+ // also the documentation. Header rows are no-ops when selected.
2859
+ const rows = [
2860
+ "── Keep-going ──",
2861
+ `Auto-resume on load — ${show("autoResume", "default")} — on: resume on session load too · off: never · default: hold on load, resume on reload/fork`,
2862
+ `Auto-accept drafts — ${show("autoAcceptDrafts", "(off)")} — on: goal/loop drafts activate without the Confirm dialog (unattended rigs)`,
2863
+ `Aggressive mode — ${show("aggressiveMode", "(off)")} — flips DEFAULTS toward keep-going (autoResume, cap 10, stuck 10, wedge off, quota auto-retry, cap→TODOs); explicit per-key settings still win`,
2864
+ "── Auditor ──",
2865
+ `Auditor model — ${show("auditorModel", "(pi session model)")} — provider/model override for the isolated auditor`,
2866
+ `Auditor thinking — ${show("auditorThinkingLevel", "(session, floor high)")} — thinking level for the auditor session`,
2867
+ `Audit cap — ${show("auditCap", "(5)")} — pause the goal after N consecutive disapprovals (0 = unlimited)`,
2868
+ `Audit feedback chars — ${show("auditFeedbackChars", "(full report)")} — cap the executor-visible disapproval report (0 = full report)`,
2869
+ `Quota retry minutes — ${show("quotaRetryMinutes", `(${DEFAULT_QUOTA_RETRY_MINUTES})`)} — auto-retry a quota-exhausted auditor after N minutes`,
2870
+ "── Stall brakes ──",
2871
+ `Wedge alert minutes — ${show("wedgeAlertMinutes", `(${WEDGE_ALERT_DEFAULT_MINUTES})`)} — hung-command alert while the session is busy (0 = off)`,
2872
+ `Stuck max interventions — ${show("stuckMaxInterventions", "(5)")} — consecutive stuck interventions before a loop stops`,
2873
+ `Stall escalation refires — ${show("stallEscalationRefires", "(5)")} — heartbeat refires with no turn before the goal pauses / loop stops (0 = never)`,
2874
+ "── Subagents ──",
2875
+ `Subagent model strategy — ${show("subagentModelStrategy", "(inherit-parent)")} — inherit-parent shares your session model+quota; agent-default pins haiku for Explore`,
2876
+ `Subagent Explore pin — ${settings.subagentModelOverrides?.Explore ?? "(follows strategy)"} — provider/model pin; always wins over strategy`,
2877
+ `Subagent Plan pin — ${settings.subagentModelOverrides?.Plan ?? "(follows strategy)"} — provider/model pin; always wins over strategy`,
2878
+ `Subagent general-purpose pin — ${settings.subagentModelOverrides?.["general-purpose"] ?? "(follows strategy)"} — provider/model pin; always wins over strategy`,
2879
+ "── Other ──",
2880
+ `Notify command — ${show("notifyCmd", "(off)")} — desktop push command; the event message is passed as $1`,
2881
+ `Token limit per goal — ${show("tokenLimit", "(off)")} — per-goal token budget; pause when exceeded (0 = off)`,
2882
+ `Reviewer config… — open the reviewer menu (post-completion follow-up enqueuer: mode, triggers, cascade, caps)`,
2883
+ "Done",
2884
+ ];
2855
2885
  let choice: string | undefined;
2856
2886
  try {
2857
2887
  choice = await ctx.ui.select(
2858
2888
  `pi-goal-list-loop-audit settings — global: ${globalSettingsPath()}`,
2859
- [
2860
- `Auditor model override — ${show("auditorModel", "(pi session model)")}`,
2861
- `Auditor thinking — ${show("auditorThinkingLevel", "(session, floor high)")}`,
2862
- `Notify command — ${show("notifyCmd", "(off)")}`,
2863
- `Token limit per goal — ${show("tokenLimit", "(off)")}`,
2864
- `Wedge alert minutes — ${show("wedgeAlertMinutes", `(${WEDGE_ALERT_DEFAULT_MINUTES}m default)`)}`,
2865
- `Aggressive mode — ${show("aggressiveMode", "(off)")}`,
2866
- `Quota retry minutes — ${show("quotaRetryMinutes", `(${DEFAULT_QUOTA_RETRY_MINUTES}m default)`)}`,
2867
- `Stuck max interventions — ${show("stuckMaxInterventions", "(5 default)")}`,
2868
- `Subagent model strategy — ${show("subagentModelStrategy", "(inherit-parent)")}`,
2869
- `Subagent Explore model pin — ${loadSettings(ctx.cwd).subagentModelOverrides?.Explore ?? "(follows strategy)"}`,
2870
- `Subagent Plan model pin — ${loadSettings(ctx.cwd).subagentModelOverrides?.Plan ?? "(follows strategy)"}`,
2871
- `Subagent general-purpose model pin — ${loadSettings(ctx.cwd).subagentModelOverrides?.["general-purpose"] ?? "(follows strategy)"}`,
2872
- `Audit feedback characters — ${show("auditFeedbackChars", "(full report)")}`,
2873
- "Done",
2874
- ],
2889
+ rows,
2875
2890
  );
2876
2891
  } catch {
2877
2892
  return;
2878
2893
  }
2879
2894
  if (!choice || choice === "Done") return;
2895
+ if (choice.startsWith("──")) continue; // section header — no-op
2880
2896
  try {
2881
- if (choice.startsWith("Auditor model")) {
2897
+ if (choice.startsWith("Auto-resume")) {
2898
+ const v = await ctx.ui.select("Auto-resume goals/loops on session start", [
2899
+ "default — HOLD when a session is loaded (popup shows what waits); auto-resume on reload/fork so machinery never strands work",
2900
+ "on — auto-resume on EVERY session start (unattended rigs)",
2901
+ "off — never auto-resume; always wait for an explicit resume",
2902
+ ]);
2903
+ if (v) saveSettings("global", ctx.cwd, { autoResume: v.startsWith("on") ? true : v.startsWith("off") ? false : undefined });
2904
+ } else if (choice.startsWith("Auto-accept drafts")) {
2905
+ const v = await ctx.ui.select("Auto-accept goal/loop drafts", [
2906
+ "off — the Confirm dialog gates every draft",
2907
+ "on — drafts activate immediately, no Confirm (unattended rigs)",
2908
+ ]);
2909
+ if (v) saveSettings("global", ctx.cwd, { autoAcceptDrafts: v.startsWith("on") ? true : undefined });
2910
+ } else if (choice.startsWith("Aggressive mode")) {
2911
+ const v = await ctx.ui.select("Aggressive mode (flips DEFAULTS toward keep-going — explicit per-key settings still win)", [
2912
+ "off — current behavior: pause at the audit cap, wedge alerts on, manual resume",
2913
+ "on — autoResume, audit cap 10, stuck max 10, wedge alerts off, quota auto-retry, cap disapprovals become a TODO list and the goal KEEPS GOING",
2914
+ ]);
2915
+ if (v) {
2916
+ saveSettings("global", ctx.cwd, { aggressiveMode: v.startsWith("on") });
2917
+ ctx.ui.notify(`Aggressive mode ${v.startsWith("on") ? "ON — goals keep going past the audit cap; objections become TODOs" : "off"}.`, "info");
2918
+ }
2919
+ } else if (choice.startsWith("Auditor model")) {
2882
2920
  const v = await ctx.ui.input("Auditor model override", "provider/model-id — empty keeps the pi session model");
2883
2921
  if (v !== undefined) saveSettings("global", ctx.cwd, { auditorModel: v.trim() || undefined });
2884
2922
  } else if (choice.startsWith("Auditor thinking")) {
2885
2923
  const v = await ctx.ui.select("Auditor thinking level", ["off", "minimal", "low", "medium", "high", "xhigh"]);
2886
2924
  if (v) saveSettings("global", ctx.cwd, { auditorThinkingLevel: v as Settings["auditorThinkingLevel"] });
2887
- } else if (choice.startsWith("Notify command")) {
2888
- const v = await ctx.ui.input("Notify command the event message is passed as $1", "e.g. a desktop-notification or push command; empty = off");
2889
- if (v !== undefined) saveSettings("global", ctx.cwd, { notifyCmd: v.trim() || undefined });
2890
- } else if (choice.startsWith("Token limit")) {
2891
- const v = await ctx.ui.input("Per-goal token budget", "non-negative integer; 0 or empty = off (no cap)");
2925
+ } else if (choice.startsWith("Audit cap")) {
2926
+ const v = await ctx.ui.input("Consecutive auditor disapprovals before the goal pauses", "non-negative integer; 0 = unlimited, empty = default 5");
2892
2927
  if (v !== undefined) {
2893
2928
  const n = Number.parseInt(v.trim(), 10);
2894
- if (Number.isFinite(n) && n >= 0) saveSettings("global", ctx.cwd, { tokenLimit: n });
2895
- else if (!v.trim()) saveSettings("global", ctx.cwd, { tokenLimit: undefined });
2929
+ if (Number.isFinite(n) && n >= 0) saveSettings("global", ctx.cwd, { auditCap: n });
2930
+ else if (!v.trim()) saveSettings("global", ctx.cwd, { auditCap: undefined });
2896
2931
  else ctx.ui.notify(`Not a non-negative integer: ${v}`, "warning");
2897
2932
  }
2898
- } else if (choice.startsWith("Wedge alert")) {
2899
- const v = await ctx.ui.input("Wedge alert threshold (minutes)", "non-negative integer; 0 = off, empty = default 30");
2933
+ } else if (choice.startsWith("Audit feedback")) {
2934
+ const v = await ctx.ui.input("Auditor feedback returned to the executor (characters)", "non-negative integer cap; 0 or empty = full report (default)");
2900
2935
  if (v !== undefined) {
2901
- const n = Number.parseInt(v.trim(), 10);
2902
- if (Number.isFinite(n) && n >= 0) saveSettings("global", ctx.cwd, { wedgeAlertMinutes: n });
2903
- else if (!v.trim()) saveSettings("global", ctx.cwd, { wedgeAlertMinutes: undefined });
2936
+ const raw = v.trim();
2937
+ const n = Number(raw);
2938
+ if (/^\d+$/.test(raw) && Number.isSafeInteger(n)) saveSettings("global", ctx.cwd, { auditFeedbackChars: n });
2939
+ else if (!v.trim()) saveSettings("global", ctx.cwd, { auditFeedbackChars: undefined });
2904
2940
  else ctx.ui.notify(`Not a non-negative integer: ${v}`, "warning");
2905
2941
  }
2906
- } else if (choice.startsWith("Aggressive mode")) {
2907
- const v = await ctx.ui.select("Aggressive mode (flips DEFAULTS toward keep-going — explicit per-key settings still win)", [
2908
- "off — current behavior: pause at the audit cap, wedge alerts on, manual resume",
2909
- "on — autoResume, audit cap 10, stuck max 10, wedge alerts off, quota auto-retry, cap disapprovals become a TODO list and the goal KEEPS GOING",
2910
- ]);
2911
- if (v) {
2912
- saveSettings("global", ctx.cwd, { aggressiveMode: v.startsWith("on") });
2913
- ctx.ui.notify(`Aggressive mode ${v.startsWith("on") ? "ON — goals keep going past the audit cap; objections become TODOs" : "off"}.`, "info");
2914
- }
2915
2942
  } else if (choice.startsWith("Quota retry minutes")) {
2916
2943
  const v = await ctx.ui.input("Minutes before auto-retrying a quota-exhausted auditor", `positive integer; empty = default ${DEFAULT_QUOTA_RETRY_MINUTES}`);
2917
2944
  if (v !== undefined) {
@@ -2920,6 +2947,14 @@ async function openSettingsUI(ctx: ExtensionContext): Promise<void> {
2920
2947
  else if (!v.trim()) saveSettings("global", ctx.cwd, { quotaRetryMinutes: undefined });
2921
2948
  else ctx.ui.notify(`Not a positive integer: ${v}`, "warning");
2922
2949
  }
2950
+ } else if (choice.startsWith("Wedge alert")) {
2951
+ const v = await ctx.ui.input("Wedge alert threshold (minutes)", "non-negative integer; 0 = off, empty = default 30");
2952
+ if (v !== undefined) {
2953
+ const n = Number.parseInt(v.trim(), 10);
2954
+ if (Number.isFinite(n) && n >= 0) saveSettings("global", ctx.cwd, { wedgeAlertMinutes: n });
2955
+ else if (!v.trim()) saveSettings("global", ctx.cwd, { wedgeAlertMinutes: undefined });
2956
+ else ctx.ui.notify(`Not a non-negative integer: ${v}`, "warning");
2957
+ }
2923
2958
  } else if (choice.startsWith("Stuck max interventions")) {
2924
2959
  const v = await ctx.ui.input("Consecutive stuck interventions before a loop stops", "positive integer; empty = default 5 (10 under aggressiveMode)");
2925
2960
  if (v !== undefined) {
@@ -2928,6 +2963,14 @@ async function openSettingsUI(ctx: ExtensionContext): Promise<void> {
2928
2963
  else if (!v.trim()) saveSettings("global", ctx.cwd, { stuckMaxInterventions: undefined });
2929
2964
  else ctx.ui.notify(`Not a positive integer: ${v}`, "warning");
2930
2965
  }
2966
+ } else if (choice.startsWith("Stall escalation")) {
2967
+ const v = await ctx.ui.input("Heartbeat refires without a turn before the goal pauses / loop stops", "non-negative integer; 0 = never escalate, empty = default 5");
2968
+ if (v !== undefined) {
2969
+ const n = Number.parseInt(v.trim(), 10);
2970
+ if (Number.isFinite(n) && n >= 0) saveSettings("global", ctx.cwd, { stallEscalationRefires: n });
2971
+ else if (!v.trim()) saveSettings("global", ctx.cwd, { stallEscalationRefires: undefined });
2972
+ else ctx.ui.notify(`Not a non-negative integer: ${v}`, "warning");
2973
+ }
2931
2974
  } else if (choice.startsWith("Subagent model strategy")) {
2932
2975
  const v = await ctx.ui.select("Subagent model (pi-subagents default agents)", [
2933
2976
  "inherit-parent — subagents share your session model + its quota pool (fixes separate-provider 403s; search agents may run on a pricier model)",
@@ -2938,8 +2981,8 @@ async function openSettingsUI(ctx: ExtensionContext): Promise<void> {
2938
2981
  saveSettings("global", ctx.cwd, { subagentModelStrategy: strategy });
2939
2982
  ctx.ui.notify("Subagent model strategy saved — applies to NEW pi sessions (pi-subagents registers agents at session start).", "info");
2940
2983
  }
2941
- } else if (/^Subagent (Explore|Plan|general-purpose) model pin/.test(choice)) {
2942
- const agentType = choice.match(/^Subagent (Explore|Plan|general-purpose) model pin/)![1]!;
2984
+ } else if (/^Subagent (Explore|Plan|general-purpose) pin/.test(choice)) {
2985
+ const agentType = choice.match(/^Subagent (Explore|Plan|general-purpose) pin/)![1]!;
2943
2986
  const v = await ctx.ui.input(`Model pin for ${agentType} subagents`, "provider/model-id e.g. minimax/MiniMax-M3 — always wins over strategy; empty = follow strategy");
2944
2987
  if (v !== undefined) {
2945
2988
  const current = loadSettings(ctx.cwd).subagentModelOverrides ?? {};
@@ -2949,15 +2992,19 @@ async function openSettingsUI(ctx: ExtensionContext): Promise<void> {
2949
2992
  saveSettings("global", ctx.cwd, { subagentModelOverrides: Object.keys(next).length > 0 ? next : undefined });
2950
2993
  ctx.ui.notify(`${agentType} model pin saved — applies to NEW pi sessions.`, "info");
2951
2994
  }
2952
- } else if (choice.startsWith("Audit feedback")) {
2953
- const v = await ctx.ui.input("Auditor feedback returned to the executor (characters)", "non-negative integer cap; 0 or empty = full report (default)");
2995
+ } else if (choice.startsWith("Notify command")) {
2996
+ const v = await ctx.ui.input("Notify command the event message is passed as $1", "e.g. a desktop-notification or push command; empty = off");
2997
+ if (v !== undefined) saveSettings("global", ctx.cwd, { notifyCmd: v.trim() || undefined });
2998
+ } else if (choice.startsWith("Token limit")) {
2999
+ const v = await ctx.ui.input("Per-goal token budget", "non-negative integer; 0 or empty = off (no cap)");
2954
3000
  if (v !== undefined) {
2955
- const raw = v.trim();
2956
- const n = Number(raw);
2957
- if (/^\d+$/.test(raw) && Number.isSafeInteger(n)) saveSettings("global", ctx.cwd, { auditFeedbackChars: n });
2958
- else if (!v.trim()) saveSettings("global", ctx.cwd, { auditFeedbackChars: undefined });
3001
+ const n = Number.parseInt(v.trim(), 10);
3002
+ if (Number.isFinite(n) && n >= 0) saveSettings("global", ctx.cwd, { tokenLimit: n });
3003
+ else if (!v.trim()) saveSettings("global", ctx.cwd, { tokenLimit: undefined });
2959
3004
  else ctx.ui.notify(`Not a non-negative integer: ${v}`, "warning");
2960
3005
  }
3006
+ } else if (choice.startsWith("Reviewer config")) {
3007
+ await cmdReviewerSettings(ctx);
2961
3008
  }
2962
3009
  } catch {
2963
3010
  return;
@@ -3161,6 +3208,8 @@ async function cmdSettings(args: string, ctx: ExtensionContext): Promise<void> {
3161
3208
  fmt("aggressiveMode", "aggressiveMode"),
3162
3209
  fmt("quotaRetryMinutes", "quotaRetryMinutes"),
3163
3210
  fmt("stuckMaxInterventions", "stuckMaxInterventions"),
3211
+ fmt("stallEscalationRefires", "stallEscalation"),
3212
+ fmt("wedgeAlertMinutes", "wedgeAlert"),
3164
3213
  // v0.25.6: effective per-type subagent model resolution.
3165
3214
  ...["Explore", "Plan", "general-purpose"].map(
3166
3215
  (t) => `subagent ${t}: ${resolveEffectiveSubagentModel(t, loadSettings(ctx.cwd), (ctx.model as any)?.id ? `${(ctx.model as any).provider}/${(ctx.model as any).id}` : undefined)}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goal-list-loop-audit",
3
- "version": "0.26.9",
3
+ "version": "0.27.0",
4
4
  "description": "Goal. Loop. Audit. Done. — 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 — only the read tools needed to verify your goal.",
5
5
  "license": "MIT",
6
6
  "author": "dracon",