pi-goal-list-loop-audit 0.25.3 → 0.25.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.
@@ -159,7 +159,9 @@ function buildGoalAuditorPrompt(goal: Goal, completionSummary: string | null | u
159
159
  ? ["4. Verify that the executor has satisfied every item in the <verification_contract>. If any item is missing or weakly addressed, disapprove."]
160
160
  : []),
161
161
  "5. Explain missing or weak evidence, especially scaffold-vs-final quality gaps.",
162
- "6. End with exactly <approved/> only if the objective is truly complete; <impossible>reason</impossible> if it can never be satisfied as stated; otherwise end with exactly <disapproved/>.",
162
+ "6. When you disapprove, end the report body with a '## Required fixes' section: one line per blocking gap, each an actionable instruction the executor can complete (most critical first). This tail is what the executor sees first — make it self-sufficient.",
163
+ "7. Write the report in English, and never emit <think> blocks or fragments — your reasoning stays private; the report is the verdict plus evidence.",
164
+ "8. End with exactly <approved/> only if the objective is truly complete; <impossible>reason</impossible> if it can never be satisfied as stated; otherwise end with exactly <disapproved/>.",
163
165
  ...(goal.verificationContract?.trim()
164
166
  ? [
165
167
  "",
@@ -309,8 +309,14 @@ export const DEFAULT_AUDIT_FEEDBACK_CHARS = 0;
309
309
  * Bound the auditor report returned to the executor after disapproval.
310
310
  * A limit of 0 explicitly means "show the full report".
311
311
  */
312
+ /** Executor-visible excerpt of a disapproval report. Full by default
313
+ * (maxChars 0). When capped, keep the TAIL: since v0.25.4 the auditor
314
+ * ends disapprovals with the actionable `## Required fixes` section —
315
+ * head-slicing would cut exactly what the executor needs. */
312
316
  export function auditFeedbackExcerpt(output: string, maxChars: number): string {
313
- return maxChars === 0 ? output : output.slice(0, maxChars);
317
+ if (maxChars === 0 || output.length <= maxChars) return output;
318
+ return `[head truncated — full report via /goal status]
319
+ …${output.slice(-maxChars)}`;
314
320
  }
315
321
 
316
322
  export interface ListItem {
@@ -400,10 +406,19 @@ export interface State {
400
406
  /** v0.24.2: count TRAILING consecutive disapprovals (the disapproval-cap
401
407
  * input). Shield-blocks (approved:true) and infra errors (neither flag)
402
408
  * break the streak — they are not verdicts on the work. */
409
+ /** v0.24.2: count TRAILING consecutive disapprovals (the disapproval-cap
410
+ * input). Shield-blocks (approved:true) break the streak — the work was
411
+ * judged good. v0.25.4: pure infra errors (error set, neither verdict
412
+ * flag) are TRANSPARENT, not streak-breakers — the auditor never judged
413
+ * the work, so D,D,infra,D is still 3 trailing disapprovals (before, 39
414
+ * hegemon-style infra errors would reset the cap and re-open infinite
415
+ * re-continuation). */
403
416
  export function countTrailingDisapprovals(history: AuditVerdict[]): number {
404
417
  let n = 0;
405
418
  for (let i = history.length - 1; i >= 0; i--) {
406
- if (history[i]!.disapproved) n++;
419
+ const v = history[i]!;
420
+ if (v.disapproved) n++;
421
+ else if (v.error && !v.approved) continue; // infra: not a verdict
407
422
  else break;
408
423
  }
409
424
  return n;
@@ -1044,3 +1059,145 @@ export function formatListDepth(stats: ListDepthStats): string {
1044
1059
  if (stats.durationSamples > 0) lines.push(`avg item duration: ${fmtAge(stats.avgDurationMs!)} (from last ${stats.durationSamples} archived)`);
1045
1060
  return lines.join("\n");
1046
1061
  }
1062
+
1063
+ // =================================================================
1064
+ // v0.25.4: auditor polish — durable audit log, think-block hygiene,
1065
+ // actionable-tail slicing, infra-transparent streaks
1066
+ // =================================================================
1067
+
1068
+ /** Strip think-block leakage from auditor reports before storage/display.
1069
+ * Motivation (wild, 2026-07-25): MiniMax-M3 reports arrive with
1070
+ * `<think>...</think>` bodies, stray `</think>` fragments, and non-English
1071
+ * reasoning spillover — the executor's feedback should be the verdict,
1072
+ * not the auditor's private monologue. */
1073
+ export function stripThinkBlocks(text: string): string {
1074
+ return text
1075
+ .replace(/<think>[\s\S]*?<\/think>/gi, "")
1076
+ .replace(/<\/?think>/gi, "")
1077
+ .replace(/<200b>/g, "") // stray partial-tag artifact seen in the wild
1078
+ .replace(/^\s+/, "");
1079
+ }
1080
+
1081
+ /** One durable audit-log entry — survives state-snapshot rotation, so
1082
+ * /glla audits can answer "where are we weak" across the whole project. */
1083
+ export interface AuditLogEntry {
1084
+ at: string;
1085
+ goalId: string;
1086
+ objective: string;
1087
+ verdict: "approved" | "disapproved" | "impossible" | "shield_blocked" | "error";
1088
+ model: string;
1089
+ thinkingLevel: string;
1090
+ report: string;
1091
+ impossibleReason?: string;
1092
+ error?: string;
1093
+ /** v0.25.4 post-audit: how long the audit took, and whether the infra
1094
+ * retry fired. */
1095
+ durationMs?: number;
1096
+ retriedOnce?: boolean;
1097
+ }
1098
+
1099
+ export function auditLogPath(cwd: string): string {
1100
+ return path.join(cwd, ".pi-glla", "audits.jsonl");
1101
+ }
1102
+
1103
+ export function appendAuditLog(cwd: string, entry: AuditLogEntry): void {
1104
+ try {
1105
+ ensureDirs(cwd);
1106
+ fs.appendFileSync(auditLogPath(cwd), JSON.stringify(entry) + "\n");
1107
+ } catch {
1108
+ /* log best-effort — never block the verdict path */
1109
+ }
1110
+ }
1111
+
1112
+ export function readAuditLog(cwd: string, limit?: number): AuditLogEntry[] {
1113
+ let raw: string;
1114
+ try {
1115
+ raw = fs.readFileSync(auditLogPath(cwd), "utf-8");
1116
+ } catch {
1117
+ return [];
1118
+ }
1119
+ const out: AuditLogEntry[] = [];
1120
+ for (const line of raw.split("\n")) {
1121
+ const t = line.trim();
1122
+ if (!t) continue;
1123
+ try {
1124
+ const e = JSON.parse(t);
1125
+ if (e && typeof e.goalId === "string" && typeof e.verdict === "string") out.push(e as AuditLogEntry);
1126
+ } catch {
1127
+ /* skip malformed */
1128
+ }
1129
+ }
1130
+ return limit !== undefined ? out.slice(-limit) : out;
1131
+ }
1132
+
1133
+ const VERDICT_GLYPH: Record<AuditLogEntry["verdict"], string> = {
1134
+ approved: "✔",
1135
+ disapproved: "✖",
1136
+ impossible: "⛔",
1137
+ shield_blocked: "🛡",
1138
+ error: "⚠",
1139
+ };
1140
+
1141
+ /** /glla audits list view: one line per verdict, newest last. */
1142
+ export function formatAuditLog(entries: AuditLogEntry[]): string {
1143
+ if (entries.length === 0) return "(no audits logged yet — the log starts with the next verdict)";
1144
+ return entries
1145
+ .map((e) => {
1146
+ const day = e.at.slice(5, 16).replace("T", " ");
1147
+ const firstLine = (e.report.split("\n").find((l) => l.trim()) ?? "").trim().slice(0, 90);
1148
+ return `${VERDICT_GLYPH[e.verdict]} ${day} [${e.goalId.slice(-6)}] ${e.model} — ${firstLine}`;
1149
+ })
1150
+ .join("\n");
1151
+ }
1152
+
1153
+ // =================================================================
1154
+ // v0.25.4 (post-audit fix): infra-failure retry-once-with-backoff
1155
+ // =================================================================
1156
+
1157
+ /** Which auditor infra errors are worth an automatic retry? User aborts
1158
+ * and missing-model config are NOT — retrying can't help them. */
1159
+ export function isRetriableInfraError(error?: string): boolean {
1160
+ if (!error) return false;
1161
+ if (/aborted/i.test(error)) return false;
1162
+ if (/no model/i.test(error)) return false;
1163
+ return true;
1164
+ }
1165
+
1166
+ export interface InfraRetryOutcome<T> {
1167
+ result: T;
1168
+ retriedOnce: boolean;
1169
+ }
1170
+
1171
+ /** Run the auditor; on a retriable infra failure, wait `backoffMs` and
1172
+ * retry EXACTLY once before reporting "auditor infrastructure error
1173
+ * (retried once)". The failed pair is never a verdict on the work. */
1174
+ export async function runWithInfraRetry<T extends { error?: string; approved: boolean; disapproved: boolean }>(
1175
+ run: () => Promise<T>,
1176
+ opts: { backoffMs?: number; sleep?: (ms: number) => Promise<void>; onRetry?: (error: string) => void } = {},
1177
+ ): Promise<InfraRetryOutcome<T>> {
1178
+ const sleep = opts.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));
1179
+ const first = await run();
1180
+ if (first.approved || first.disapproved || !isRetriableInfraError(first.error)) {
1181
+ return { result: first, retriedOnce: false };
1182
+ }
1183
+ opts.onRetry?.(first.error!);
1184
+ await sleep(opts.backoffMs ?? 5000);
1185
+ const second = await run();
1186
+ return { result: second, retriedOnce: true };
1187
+ }
1188
+
1189
+ /** /glla audits default view: the ACTIVE goal's own audit history (the
1190
+ * surface the goal spec asked for), one line per verdict. */
1191
+ export function formatGoalAuditHistory(goal: { id: string; auditHistory?: Array<any> }): string {
1192
+ const history = goal.auditHistory ?? [];
1193
+ if (history.length === 0) return "(no audits on this goal yet)";
1194
+ return history
1195
+ .map((v) => {
1196
+ const glyph = v.approved ? (v.regressionShieldPassed === false ? "🛡" : "✔") : v.impossible ? "⛔" : v.disapproved ? "✖" : "⚠";
1197
+ const day = String(v.at ?? "").slice(5, 16).replace("T", " ");
1198
+ const elapsed = v.durationMs ? ` · ${Math.round(v.durationMs / 60000)}m` : "";
1199
+ const firstLine = (String(v.report ?? "").split("\n").find((l: string) => l.trim()) ?? "").trim().slice(0, 80);
1200
+ return `${glyph} ${day} ${v.model ?? "?"}${elapsed} — ${firstLine}`;
1201
+ })
1202
+ .join("\n");
1203
+ }
@@ -72,6 +72,9 @@ export interface AuditDisplayProgress {
72
72
  currentTool?: string;
73
73
  label?: string;
74
74
  elapsedMs?: number;
75
+ /** v0.25.4: last progress-event time — the widget flags auditor-quiet
76
+ * stalls when this goes stale while the audit is in flight. */
77
+ lastEventAt?: number;
75
78
  }
76
79
 
77
80
  /**
@@ -175,7 +178,12 @@ function goalLines(g: Goal, state: State, audit: AuditDisplayProgress | null | u
175
178
  const lines = [head, `├─ ${isList ? "list item · " : ""}${statusWord} · ${fmtElapsed(now - Date.parse(g.createdAt))}${tokens}`];
176
179
  if (g.status === "auditing") {
177
180
  lines.push(`├─ auditor: ${audit?.label ?? "running"}${audit?.currentTool ? ` · ${truncate(audit.currentTool, 30)}` : ""}`);
178
- if (audit?.elapsedMs) lines.push(`└─ ${paint(theme, "dim", `${fmtElapsed(audit.elapsedMs)} in isolated session`)}`);
181
+ // v0.25.4: auditor-quiet stall progress events stopped arriving
182
+ // while the audit is in flight (hung model call, stuck tool).
183
+ const quietMs = audit?.lastEventAt !== undefined ? now - audit.lastEventAt : 0;
184
+ if (quietMs > 3 * 60_000) {
185
+ lines.push(`└─ ${paint(theme, "warning", `auditor quiet ${fmtElapsed(quietMs)} — may be stuck; Esc aborts, verdict is not counted`)}`);
186
+ } else if (audit?.elapsedMs) lines.push(`└─ ${paint(theme, "dim", `${fmtElapsed(audit.elapsedMs)} in isolated session`)}`);
179
187
  else lines.push(`└─ ${paint(theme, "dim", "isolated session, read-only tools")}`);
180
188
  return lines;
181
189
  }
@@ -39,7 +39,14 @@ import {
39
39
  isFullAuditObjective,
40
40
  lastShippedAtMs,
41
41
  resolveEffectiveAggressiveSettings,
42
+ appendAuditLog,
42
43
  computeListDepth,
44
+ formatAuditLog,
45
+ formatGoalAuditHistory,
46
+ runWithInfraRetry,
47
+ readAuditLog,
48
+ stripThinkBlocks,
49
+ type AuditLogEntry,
43
50
  ledgerPath,
44
51
  crossRecommendMode,
45
52
  formatListDepth,
@@ -1697,24 +1704,39 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
1697
1704
  ctx.ui.notify(`Auditor running (isolated session, model: ${via ?? "setting"})…`, "info");
1698
1705
  // Esc during the audit aborts this tool's signal → threaded into the
1699
1706
  // auditor session, which aborts cleanly and returns "Auditor aborted."
1700
- latestAuditProgress = { label: "starting" };
1701
- const result = await runGoalCompletionAuditor({
1702
- ctx,
1703
- goal: state.goal,
1704
- completionSummary: p.completionSummary,
1705
- verificationSummary: p.verificationSummary,
1706
- model: auditorModel,
1707
- thinkingLevel: settings.auditorThinkingLevel ?? getSessionThinkingLevel(),
1708
- signal: signal ?? undefined,
1709
- onProgress: (progress) => {
1710
- latestAuditProgress = {
1711
- currentTool: progress.currentTool,
1712
- label: progress.label,
1713
- elapsedMs: progress.elapsedMs,
1714
- };
1707
+ latestAuditProgress = { label: "starting", lastEventAt: Date.now() };
1708
+ const runAudit = () =>
1709
+ runGoalCompletionAuditor({
1710
+ ctx,
1711
+ goal: state.goal!,
1712
+ completionSummary: p.completionSummary,
1713
+ verificationSummary: p.verificationSummary,
1714
+ model: auditorModel,
1715
+ thinkingLevel: settings.auditorThinkingLevel ?? getSessionThinkingLevel(),
1716
+ signal: signal ?? undefined,
1717
+ onProgress: (progress) => {
1718
+ latestAuditProgress = {
1719
+ currentTool: progress.currentTool,
1720
+ label: progress.label,
1721
+ elapsedMs: progress.elapsedMs,
1722
+ lastEventAt: Date.now(),
1723
+ };
1724
+ refreshUI(ctx);
1725
+ },
1726
+ });
1727
+ // v0.25.4 (post-audit fix): a retriable infra failure (stream error,
1728
+ // auth blip — NOT user abort, NOT missing model) gets ONE automatic
1729
+ // retry with backoff before we report "auditor infrastructure error
1730
+ // (retried once)". Neither attempt is a verdict on the work.
1731
+ const auditStartMs = Date.now();
1732
+ const { result, retriedOnce } = await runWithInfraRetry(runAudit, {
1733
+ onRetry: (err) => {
1734
+ latestAuditProgress = { label: `infra error (${err.slice(0, 40)}) — retrying once`, lastEventAt: Date.now() };
1715
1735
  refreshUI(ctx);
1736
+ appendLedger(ctx.cwd, "audit_infra_retry", { goalId: state.goal?.id, error: err.slice(0, 200) });
1716
1737
  },
1717
1738
  });
1739
+ const auditDurationMs = Date.now() - auditStartMs;
1718
1740
  latestAuditProgress = null;
1719
1741
  // Audit history: record REAL verdicts only — a non-empty report is the
1720
1742
  // evidence the auditor actually inspected something. Empty-report runs
@@ -1723,6 +1745,11 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
1723
1745
  const auditorRan = result.output.trim().length > 0;
1724
1746
  const history = state.goal.auditHistory ?? [];
1725
1747
  if (auditorRan) {
1748
+ // v0.25.4: strip think-block leakage (MiniMax-M3 `</think>`
1749
+ // fragments + reasoning spillover) before anything stores or
1750
+ // displays the report.
1751
+ const cleanOutput = stripThinkBlocks(result.output);
1752
+ result.output = cleanOutput;
1726
1753
  history.push({
1727
1754
  at: nowIso(),
1728
1755
  approved: result.approved,
@@ -1731,13 +1758,39 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
1731
1758
  impossibleReason: result.impossibleReason,
1732
1759
  model: result.model,
1733
1760
  thinkingLevel: result.thinkingLevel,
1734
- report: result.output,
1761
+ report: cleanOutput,
1735
1762
  error: result.error,
1736
1763
  regressionShieldPassed: result.regressionShieldPassed,
1737
1764
  regressionShieldMissing: result.regressionShieldMissing,
1738
- });
1765
+ durationMs: auditDurationMs,
1766
+ } as any);
1739
1767
  // Cap history — 39 infra errors taught us unbounded growth is real.
1740
1768
  if (history.length > 20) history.splice(0, history.length - 20);
1769
+ // v0.25.4: durable append-only audit log — survives state-snapshot
1770
+ // rotation; the review surface for "where are we weak".
1771
+ const verdict: AuditLogEntry["verdict"] =
1772
+ result.error && !result.approved && !result.disapproved
1773
+ ? "error"
1774
+ : result.approved && result.regressionShieldPassed === false
1775
+ ? "shield_blocked"
1776
+ : result.approved
1777
+ ? "approved"
1778
+ : result.impossible
1779
+ ? "impossible"
1780
+ : "disapproved";
1781
+ appendAuditLog(ctx.cwd, {
1782
+ at: nowIso(),
1783
+ goalId: state.goal.id,
1784
+ objective: state.goal.objective.slice(0, 200),
1785
+ verdict,
1786
+ model: result.model,
1787
+ thinkingLevel: result.thinkingLevel ?? "(default)",
1788
+ report: cleanOutput,
1789
+ impossibleReason: result.impossibleReason,
1790
+ error: result.error,
1791
+ durationMs: auditDurationMs,
1792
+ retriedOnce,
1793
+ } as AuditLogEntry);
1741
1794
  }
1742
1795
 
1743
1796
  // Escape hatch: the user aborted the audit (Esc). Offer the explicit
@@ -1863,14 +1916,14 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
1863
1916
  updateGoal({
1864
1917
  status: "active",
1865
1918
  auditHistory: history,
1866
- pauseReason: `auditor infrastructure: ${result.error}`,
1919
+ pauseReason: `auditor infrastructure${retriedOnce ? " (retried once)" : ""}: ${result.error}`,
1867
1920
  pauseSuggestedAction: "Fix the auditor model (/glla model=provider/id) and call complete_goal again — your work was NOT judged",
1868
1921
  }, ctx);
1869
1922
  scheduleContinuation(ctx, true);
1870
1923
  return {
1871
1924
  content: [{
1872
1925
  type: "text",
1873
- text: `The auditor could not run (infrastructure, NOT a verdict): ${result.error}\nYour completion claim was not evaluated. Fix the auditor model with /glla model=provider/id and call complete_goal again — do not change your deliverable for this.`,
1926
+ text: `The auditor could not run (infrastructure, NOT a verdict${retriedOnce ? "; retried once with backoff, both attempts failed" : ""}): ${result.error}\nYour completion claim was not evaluated. Fix the auditor model with /glla model=provider/id and call complete_goal again — do not change your deliverable for this.`,
1874
1927
  }],
1875
1928
  details: {},
1876
1929
  };
@@ -1916,7 +1969,7 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
1916
1969
  const auditFeedbackIsFull = auditFeedbackChars === 0 || result.output.length <= auditFeedbackChars;
1917
1970
  const auditFeedbackLabel = auditFeedbackIsFull
1918
1971
  ? "full report"
1919
- : `first ${auditFeedbackChars} chars`;
1972
+ : `last ${auditFeedbackChars} chars (Required-fixes tail)`;
1920
1973
  const auditFeedbackTruncationHint = auditFeedbackIsFull
1921
1974
  ? ""
1922
1975
  : `\n\nReport truncated at the configured limit. /goal status shows the full report; change future feedback with /glla auditfeedbackchars=N (0 = full report).`;
@@ -2744,6 +2797,40 @@ function cmdStats(args: string, ctx: ExtensionContext): void {
2744
2797
  ctx.ui.notify(`glla stats — ${rollups.length} project(s)${prematureOnly ? " (premature filter)" : ""}\n${out}`, "info");
2745
2798
  }
2746
2799
 
2800
+ /**
2801
+ * v0.25.4: /glla audits [N|full] — browse the durable per-project audit
2802
+ * log (.pi-glla/audits.jsonl). Default: last 10 verdicts, one line each.
2803
+ * "full" prints the latest report in full.
2804
+ */
2805
+ function cmdAudits(args: string, ctx: ExtensionContext): void {
2806
+ const full = /\bfull\b/.test(args);
2807
+ const all = /\b(?:all|global|log)\b/.test(args);
2808
+ const nMatch = args.match(/\b(\d+)\b/);
2809
+ if (full) {
2810
+ // Latest report — active goal's history first, then the log.
2811
+ const fromGoal = state.goal?.auditHistory?.at(-1);
2812
+ if (fromGoal?.report) {
2813
+ ctx.ui.notify(`Latest audit on this goal — ${fromGoal.model} (${fromGoal.at})\n${fromGoal.report}`, "info");
2814
+ return;
2815
+ }
2816
+ const latest = readAuditLog(ctx.cwd).at(-1);
2817
+ ctx.ui.notify(latest ? `Latest audit — ${latest.verdict} (${latest.model}, ${latest.at})\n${latest.report}` : "No audits logged yet.", "info");
2818
+ return;
2819
+ }
2820
+ // Default: the ACTIVE goal's own audit history (with per-audit elapsed);
2821
+ // "all"/"global"/"log" browses the durable cross-goal log.
2822
+ if (!all && state.goal?.auditHistory && state.goal.auditHistory.length > 0) {
2823
+ ctx.ui.notify(
2824
+ `glla audits — this goal's history (${state.goal.auditHistory.length} verdict(s); /glla audits all for the project log)\n${formatGoalAuditHistory(state.goal)}`,
2825
+ "info",
2826
+ );
2827
+ return;
2828
+ }
2829
+ const n = nMatch ? Number(nMatch[1]) : 10;
2830
+ const entries = readAuditLog(ctx.cwd, n);
2831
+ ctx.ui.notify(`glla audits — last ${entries.length} verdict(s) in ${ctx.cwd}\n${formatAuditLog(entries)}`, "info");
2832
+ }
2833
+
2747
2834
  async function cmdSettings(args: string, ctx: ExtensionContext): Promise<void> {
2748
2835
  // The plugin's ONE config surface — global by default, rarely opened.
2749
2836
  // /glla show effective values + where each comes from
@@ -2762,6 +2849,10 @@ async function cmdSettings(args: string, ctx: ExtensionContext): Promise<void> {
2762
2849
  cmdStats(trimmed.slice("stats".length).trim(), ctx);
2763
2850
  return;
2764
2851
  }
2852
+ if (/^audits\b/.test(trimmed)) {
2853
+ cmdAudits(trimmed.slice("audits".length).trim(), ctx);
2854
+ return;
2855
+ }
2765
2856
  if (!trimmed) {
2766
2857
  if (ctx.hasUI) {
2767
2858
  await openSettingsUI(ctx);
@@ -3059,6 +3150,7 @@ export default function (pi: ExtensionAPI): void {
3059
3150
  ["quotaretryminutes=", "N: minutes before auto-retrying a quota-exhausted auditor (default 60)"],
3060
3151
  ["stuckmax=", "N: consecutive stuck interventions before a loop stops (default 5)"],
3061
3152
  ["stats", "per-project ledger rollups: /glla stats [json|premature|project=<path>]"],
3153
+ ["audits", "audit-log browser: /glla audits [N|full] — recent verdicts from .pi-glla/audits.jsonl"],
3062
3154
  ["autoaccept=", "on: drafts activate without the Confirm dialog (unattended rigs)"],
3063
3155
  ["project", "write a project override: /glla project key=value"],
3064
3156
  ]),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goal-list-loop-audit",
3
- "version": "0.25.3",
3
+ "version": "0.25.5",
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",