pi-goal-list-loop-audit 0.26.9 → 0.27.1
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/extensions/goal-loop-display.ts +53 -2
- package/extensions/loops/goal.ts +101 -48
- package/package.json +1 -1
|
@@ -37,6 +37,36 @@ export function truncate(s: string, max: number): string {
|
|
|
37
37
|
return s.length <= max ? s : s.slice(0, Math.max(0, max - 1)) + "…";
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Word-wrap to `width`, capped at `maxLines` (v0.27.1). A pause is the one
|
|
42
|
+
* state where the FULL text matters — the reason often carries a decision
|
|
43
|
+
* the user must make (dedup choices, impossible-verdict narrowing), and a
|
|
44
|
+
* 60-char truncate hid it. Over-long words are hard-split; when the cap
|
|
45
|
+
* cuts content the last line ends with "…" (the pause-time notification
|
|
46
|
+
* and /goal status always carry the full text).
|
|
47
|
+
*/
|
|
48
|
+
export function wrap(s: string, width: number, maxLines: number): string[] {
|
|
49
|
+
const norm = s.replace(/\s+/g, " ").trim();
|
|
50
|
+
const words = norm.split(" ").filter(Boolean);
|
|
51
|
+
const all: string[] = [];
|
|
52
|
+
let cur = "";
|
|
53
|
+
for (let w of words) {
|
|
54
|
+
const next = cur ? `${cur} ${w}` : w;
|
|
55
|
+
if (next.length <= width) { cur = next; continue; }
|
|
56
|
+
if (cur) all.push(cur);
|
|
57
|
+
while (w.length > width) { all.push(w.slice(0, width)); w = w.slice(width); }
|
|
58
|
+
cur = w;
|
|
59
|
+
}
|
|
60
|
+
if (cur) all.push(cur);
|
|
61
|
+
if (all.length === 0) all.push("");
|
|
62
|
+
if (all.length <= maxLines) return all;
|
|
63
|
+
const out = all.slice(0, maxLines);
|
|
64
|
+
// The last kept line already fits within width — truncate() would leave it
|
|
65
|
+
// unmarked, so force the ellipsis to signal "more in /goal status".
|
|
66
|
+
out[maxLines - 1] = out[maxLines - 1]!.slice(0, Math.max(0, width - 1)) + "…";
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
|
|
40
70
|
/**
|
|
41
71
|
* Width-aware truncation budget (v0.22.2). The hardcoded caps are FLOORS for
|
|
42
72
|
* narrow terminals; when the terminal is wider, lines may use the available
|
|
@@ -191,8 +221,29 @@ function goalLines(g: Goal, state: State, audit: AuditDisplayProgress | null | u
|
|
|
191
221
|
return lines;
|
|
192
222
|
}
|
|
193
223
|
if (g.status === "paused" && g.pauseReason) {
|
|
194
|
-
|
|
195
|
-
|
|
224
|
+
const isErr = pauseIsError(g);
|
|
225
|
+
const budget = budgetFor(width, 3, 60);
|
|
226
|
+
// v0.27.1: wrap reason + suggested action over up to 3 lines each
|
|
227
|
+
// (see wrap()); before, both were truncated at ~60 chars and the actual
|
|
228
|
+
// question in a decision-pause never reached the user.
|
|
229
|
+
wrap(g.pauseReason, budget, 3).forEach((w, i) => {
|
|
230
|
+
lines.push(`${i === 0 ? "├─" : "│ "} ${paint(theme, isErr ? "error" : "warning", w)}`);
|
|
231
|
+
});
|
|
232
|
+
// v0.27.1: what survives the pause — the first question at a pause is
|
|
233
|
+
// "did I lose the work?". Answer it on the card.
|
|
234
|
+
const spent: string[] = [];
|
|
235
|
+
const tokUsed = g.usage?.tokensUsed ?? 0;
|
|
236
|
+
if (tokUsed > 0) spent.push(`${fmtTokens(tokUsed)} tok spent`);
|
|
237
|
+
const audits = g.auditHistory?.length ?? 0;
|
|
238
|
+
if (audits > 0) spent.push(`${audits} audit${audits === 1 ? "" : "s"}`);
|
|
239
|
+
const savedLine = `saved${spent.length > 0 ? ` — ${spent.join(" · ")}` : ""} · resumes exactly here`;
|
|
240
|
+
if (g.pauseSuggestedAction) {
|
|
241
|
+
lines.push(`├─ ${paint(theme, "dim", truncate(savedLine, budget))}`);
|
|
242
|
+
const wrapped = wrap(g.pauseSuggestedAction, budget, 3);
|
|
243
|
+
wrapped.forEach((w, i) => lines.push(`${i === wrapped.length - 1 ? "└─" : "│ "} ${paint(theme, "dim", w)}`));
|
|
244
|
+
} else {
|
|
245
|
+
lines.push(`└─ ${paint(theme, "dim", truncate(savedLine, budget))}`);
|
|
246
|
+
}
|
|
196
247
|
return lines;
|
|
197
248
|
}
|
|
198
249
|
const next = nextPending(g);
|
package/extensions/loops/goal.ts
CHANGED
|
@@ -2254,8 +2254,12 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
2254
2254
|
pauseReason: p.reason,
|
|
2255
2255
|
pauseSuggestedAction: p.suggestedAction,
|
|
2256
2256
|
}, ctx);
|
|
2257
|
-
|
|
2258
|
-
|
|
2257
|
+
// v0.27.1: surface the FULL pause contract — reason AND suggested
|
|
2258
|
+
// action. Before, the action only appeared in /goal status and the
|
|
2259
|
+
// widget truncated both at ~60 chars, so decision-pauses ("choose a
|
|
2260
|
+
// or b") reached the user as an unreadable fragment.
|
|
2261
|
+
ctx.ui.notify(`Goal paused: ${p.reason}${p.suggestedAction ? `\n\n→ ${p.suggestedAction}` : ""}`, "info");
|
|
2262
|
+
notifyExternal(ctx, `Goal paused: ${(p.suggestedAction ? `${p.reason} → ${p.suggestedAction}` : p.reason).slice(0, 200)}`);
|
|
2259
2263
|
return { content: [{ type: "text", text: "Goal paused. /goal resume to continue." }], details: {} };
|
|
2260
2264
|
},
|
|
2261
2265
|
}));
|
|
@@ -2852,66 +2856,93 @@ async function openSettingsUI(ctx: ExtensionContext): Promise<void> {
|
|
|
2852
2856
|
const v = p.value === undefined ? fallback : String(p.value);
|
|
2853
2857
|
return `${v} [${p.source}]`;
|
|
2854
2858
|
};
|
|
2859
|
+
const settings = loadSettings(ctx.cwd);
|
|
2860
|
+
// v0.27.0: every option on ONE screen, grouped into sections, each row
|
|
2861
|
+
// carrying `label — value [provenance] — what it does` so the menu is
|
|
2862
|
+
// also the documentation. Header rows are no-ops when selected.
|
|
2863
|
+
const rows = [
|
|
2864
|
+
"── Keep-going ──",
|
|
2865
|
+
`Auto-resume on load — ${show("autoResume", "default")} — on: resume on session load too · off: never · default: hold on load, resume on reload/fork`,
|
|
2866
|
+
`Auto-accept drafts — ${show("autoAcceptDrafts", "(off)")} — on: goal/loop drafts activate without the Confirm dialog (unattended rigs)`,
|
|
2867
|
+
`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`,
|
|
2868
|
+
"── Auditor ──",
|
|
2869
|
+
`Auditor model — ${show("auditorModel", "(pi session model)")} — provider/model override for the isolated auditor`,
|
|
2870
|
+
`Auditor thinking — ${show("auditorThinkingLevel", "(session, floor high)")} — thinking level for the auditor session`,
|
|
2871
|
+
`Audit cap — ${show("auditCap", "(5)")} — pause the goal after N consecutive disapprovals (0 = unlimited)`,
|
|
2872
|
+
`Audit feedback chars — ${show("auditFeedbackChars", "(full report)")} — cap the executor-visible disapproval report (0 = full report)`,
|
|
2873
|
+
`Quota retry minutes — ${show("quotaRetryMinutes", `(${DEFAULT_QUOTA_RETRY_MINUTES})`)} — auto-retry a quota-exhausted auditor after N minutes`,
|
|
2874
|
+
"── Stall brakes ──",
|
|
2875
|
+
`Wedge alert minutes — ${show("wedgeAlertMinutes", `(${WEDGE_ALERT_DEFAULT_MINUTES})`)} — hung-command alert while the session is busy (0 = off)`,
|
|
2876
|
+
`Stuck max interventions — ${show("stuckMaxInterventions", "(5)")} — consecutive stuck interventions before a loop stops`,
|
|
2877
|
+
`Stall escalation refires — ${show("stallEscalationRefires", "(5)")} — heartbeat refires with no turn before the goal pauses / loop stops (0 = never)`,
|
|
2878
|
+
"── Subagents ──",
|
|
2879
|
+
`Subagent model strategy — ${show("subagentModelStrategy", "(inherit-parent)")} — inherit-parent shares your session model+quota; agent-default pins haiku for Explore`,
|
|
2880
|
+
`Subagent Explore pin — ${settings.subagentModelOverrides?.Explore ?? "(follows strategy)"} — provider/model pin; always wins over strategy`,
|
|
2881
|
+
`Subagent Plan pin — ${settings.subagentModelOverrides?.Plan ?? "(follows strategy)"} — provider/model pin; always wins over strategy`,
|
|
2882
|
+
`Subagent general-purpose pin — ${settings.subagentModelOverrides?.["general-purpose"] ?? "(follows strategy)"} — provider/model pin; always wins over strategy`,
|
|
2883
|
+
"── Other ──",
|
|
2884
|
+
`Notify command — ${show("notifyCmd", "(off)")} — desktop push command; the event message is passed as $1`,
|
|
2885
|
+
`Token limit per goal — ${show("tokenLimit", "(off)")} — per-goal token budget; pause when exceeded (0 = off)`,
|
|
2886
|
+
`Reviewer config… — open the reviewer menu (post-completion follow-up enqueuer: mode, triggers, cascade, caps)`,
|
|
2887
|
+
"Done",
|
|
2888
|
+
];
|
|
2855
2889
|
let choice: string | undefined;
|
|
2856
2890
|
try {
|
|
2857
2891
|
choice = await ctx.ui.select(
|
|
2858
2892
|
`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
|
-
],
|
|
2893
|
+
rows,
|
|
2875
2894
|
);
|
|
2876
2895
|
} catch {
|
|
2877
2896
|
return;
|
|
2878
2897
|
}
|
|
2879
2898
|
if (!choice || choice === "Done") return;
|
|
2899
|
+
if (choice.startsWith("──")) continue; // section header — no-op
|
|
2880
2900
|
try {
|
|
2881
|
-
if (choice.startsWith("
|
|
2901
|
+
if (choice.startsWith("Auto-resume")) {
|
|
2902
|
+
const v = await ctx.ui.select("Auto-resume goals/loops on session start", [
|
|
2903
|
+
"default — HOLD when a session is loaded (popup shows what waits); auto-resume on reload/fork so machinery never strands work",
|
|
2904
|
+
"on — auto-resume on EVERY session start (unattended rigs)",
|
|
2905
|
+
"off — never auto-resume; always wait for an explicit resume",
|
|
2906
|
+
]);
|
|
2907
|
+
if (v) saveSettings("global", ctx.cwd, { autoResume: v.startsWith("on") ? true : v.startsWith("off") ? false : undefined });
|
|
2908
|
+
} else if (choice.startsWith("Auto-accept drafts")) {
|
|
2909
|
+
const v = await ctx.ui.select("Auto-accept goal/loop drafts", [
|
|
2910
|
+
"off — the Confirm dialog gates every draft",
|
|
2911
|
+
"on — drafts activate immediately, no Confirm (unattended rigs)",
|
|
2912
|
+
]);
|
|
2913
|
+
if (v) saveSettings("global", ctx.cwd, { autoAcceptDrafts: v.startsWith("on") ? true : undefined });
|
|
2914
|
+
} else if (choice.startsWith("Aggressive mode")) {
|
|
2915
|
+
const v = await ctx.ui.select("Aggressive mode (flips DEFAULTS toward keep-going — explicit per-key settings still win)", [
|
|
2916
|
+
"off — current behavior: pause at the audit cap, wedge alerts on, manual resume",
|
|
2917
|
+
"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",
|
|
2918
|
+
]);
|
|
2919
|
+
if (v) {
|
|
2920
|
+
saveSettings("global", ctx.cwd, { aggressiveMode: v.startsWith("on") });
|
|
2921
|
+
ctx.ui.notify(`Aggressive mode ${v.startsWith("on") ? "ON — goals keep going past the audit cap; objections become TODOs" : "off"}.`, "info");
|
|
2922
|
+
}
|
|
2923
|
+
} else if (choice.startsWith("Auditor model")) {
|
|
2882
2924
|
const v = await ctx.ui.input("Auditor model override", "provider/model-id — empty keeps the pi session model");
|
|
2883
2925
|
if (v !== undefined) saveSettings("global", ctx.cwd, { auditorModel: v.trim() || undefined });
|
|
2884
2926
|
} else if (choice.startsWith("Auditor thinking")) {
|
|
2885
2927
|
const v = await ctx.ui.select("Auditor thinking level", ["off", "minimal", "low", "medium", "high", "xhigh"]);
|
|
2886
2928
|
if (v) saveSettings("global", ctx.cwd, { auditorThinkingLevel: v as Settings["auditorThinkingLevel"] });
|
|
2887
|
-
} else if (choice.startsWith("
|
|
2888
|
-
const v = await ctx.ui.input("
|
|
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)");
|
|
2929
|
+
} else if (choice.startsWith("Audit cap")) {
|
|
2930
|
+
const v = await ctx.ui.input("Consecutive auditor disapprovals before the goal pauses", "non-negative integer; 0 = unlimited, empty = default 5");
|
|
2892
2931
|
if (v !== undefined) {
|
|
2893
2932
|
const n = Number.parseInt(v.trim(), 10);
|
|
2894
|
-
if (Number.isFinite(n) && n >= 0) saveSettings("global", ctx.cwd, {
|
|
2895
|
-
else if (!v.trim()) saveSettings("global", ctx.cwd, {
|
|
2933
|
+
if (Number.isFinite(n) && n >= 0) saveSettings("global", ctx.cwd, { auditCap: n });
|
|
2934
|
+
else if (!v.trim()) saveSettings("global", ctx.cwd, { auditCap: undefined });
|
|
2896
2935
|
else ctx.ui.notify(`Not a non-negative integer: ${v}`, "warning");
|
|
2897
2936
|
}
|
|
2898
|
-
} else if (choice.startsWith("
|
|
2899
|
-
const v = await ctx.ui.input("
|
|
2937
|
+
} else if (choice.startsWith("Audit feedback")) {
|
|
2938
|
+
const v = await ctx.ui.input("Auditor feedback returned to the executor (characters)", "non-negative integer cap; 0 or empty = full report (default)");
|
|
2900
2939
|
if (v !== undefined) {
|
|
2901
|
-
const
|
|
2902
|
-
|
|
2903
|
-
|
|
2940
|
+
const raw = v.trim();
|
|
2941
|
+
const n = Number(raw);
|
|
2942
|
+
if (/^\d+$/.test(raw) && Number.isSafeInteger(n)) saveSettings("global", ctx.cwd, { auditFeedbackChars: n });
|
|
2943
|
+
else if (!v.trim()) saveSettings("global", ctx.cwd, { auditFeedbackChars: undefined });
|
|
2904
2944
|
else ctx.ui.notify(`Not a non-negative integer: ${v}`, "warning");
|
|
2905
2945
|
}
|
|
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
2946
|
} else if (choice.startsWith("Quota retry minutes")) {
|
|
2916
2947
|
const v = await ctx.ui.input("Minutes before auto-retrying a quota-exhausted auditor", `positive integer; empty = default ${DEFAULT_QUOTA_RETRY_MINUTES}`);
|
|
2917
2948
|
if (v !== undefined) {
|
|
@@ -2920,6 +2951,14 @@ async function openSettingsUI(ctx: ExtensionContext): Promise<void> {
|
|
|
2920
2951
|
else if (!v.trim()) saveSettings("global", ctx.cwd, { quotaRetryMinutes: undefined });
|
|
2921
2952
|
else ctx.ui.notify(`Not a positive integer: ${v}`, "warning");
|
|
2922
2953
|
}
|
|
2954
|
+
} else if (choice.startsWith("Wedge alert")) {
|
|
2955
|
+
const v = await ctx.ui.input("Wedge alert threshold (minutes)", "non-negative integer; 0 = off, empty = default 30");
|
|
2956
|
+
if (v !== undefined) {
|
|
2957
|
+
const n = Number.parseInt(v.trim(), 10);
|
|
2958
|
+
if (Number.isFinite(n) && n >= 0) saveSettings("global", ctx.cwd, { wedgeAlertMinutes: n });
|
|
2959
|
+
else if (!v.trim()) saveSettings("global", ctx.cwd, { wedgeAlertMinutes: undefined });
|
|
2960
|
+
else ctx.ui.notify(`Not a non-negative integer: ${v}`, "warning");
|
|
2961
|
+
}
|
|
2923
2962
|
} else if (choice.startsWith("Stuck max interventions")) {
|
|
2924
2963
|
const v = await ctx.ui.input("Consecutive stuck interventions before a loop stops", "positive integer; empty = default 5 (10 under aggressiveMode)");
|
|
2925
2964
|
if (v !== undefined) {
|
|
@@ -2928,6 +2967,14 @@ async function openSettingsUI(ctx: ExtensionContext): Promise<void> {
|
|
|
2928
2967
|
else if (!v.trim()) saveSettings("global", ctx.cwd, { stuckMaxInterventions: undefined });
|
|
2929
2968
|
else ctx.ui.notify(`Not a positive integer: ${v}`, "warning");
|
|
2930
2969
|
}
|
|
2970
|
+
} else if (choice.startsWith("Stall escalation")) {
|
|
2971
|
+
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");
|
|
2972
|
+
if (v !== undefined) {
|
|
2973
|
+
const n = Number.parseInt(v.trim(), 10);
|
|
2974
|
+
if (Number.isFinite(n) && n >= 0) saveSettings("global", ctx.cwd, { stallEscalationRefires: n });
|
|
2975
|
+
else if (!v.trim()) saveSettings("global", ctx.cwd, { stallEscalationRefires: undefined });
|
|
2976
|
+
else ctx.ui.notify(`Not a non-negative integer: ${v}`, "warning");
|
|
2977
|
+
}
|
|
2931
2978
|
} else if (choice.startsWith("Subagent model strategy")) {
|
|
2932
2979
|
const v = await ctx.ui.select("Subagent model (pi-subagents default agents)", [
|
|
2933
2980
|
"inherit-parent — subagents share your session model + its quota pool (fixes separate-provider 403s; search agents may run on a pricier model)",
|
|
@@ -2938,8 +2985,8 @@ async function openSettingsUI(ctx: ExtensionContext): Promise<void> {
|
|
|
2938
2985
|
saveSettings("global", ctx.cwd, { subagentModelStrategy: strategy });
|
|
2939
2986
|
ctx.ui.notify("Subagent model strategy saved — applies to NEW pi sessions (pi-subagents registers agents at session start).", "info");
|
|
2940
2987
|
}
|
|
2941
|
-
} else if (/^Subagent (Explore|Plan|general-purpose)
|
|
2942
|
-
const agentType = choice.match(/^Subagent (Explore|Plan|general-purpose)
|
|
2988
|
+
} else if (/^Subagent (Explore|Plan|general-purpose) pin/.test(choice)) {
|
|
2989
|
+
const agentType = choice.match(/^Subagent (Explore|Plan|general-purpose) pin/)![1]!;
|
|
2943
2990
|
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
2991
|
if (v !== undefined) {
|
|
2945
2992
|
const current = loadSettings(ctx.cwd).subagentModelOverrides ?? {};
|
|
@@ -2949,15 +2996,19 @@ async function openSettingsUI(ctx: ExtensionContext): Promise<void> {
|
|
|
2949
2996
|
saveSettings("global", ctx.cwd, { subagentModelOverrides: Object.keys(next).length > 0 ? next : undefined });
|
|
2950
2997
|
ctx.ui.notify(`${agentType} model pin saved — applies to NEW pi sessions.`, "info");
|
|
2951
2998
|
}
|
|
2952
|
-
} else if (choice.startsWith("
|
|
2953
|
-
const v = await ctx.ui.input("
|
|
2999
|
+
} else if (choice.startsWith("Notify command")) {
|
|
3000
|
+
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");
|
|
3001
|
+
if (v !== undefined) saveSettings("global", ctx.cwd, { notifyCmd: v.trim() || undefined });
|
|
3002
|
+
} else if (choice.startsWith("Token limit")) {
|
|
3003
|
+
const v = await ctx.ui.input("Per-goal token budget", "non-negative integer; 0 or empty = off (no cap)");
|
|
2954
3004
|
if (v !== undefined) {
|
|
2955
|
-
const
|
|
2956
|
-
|
|
2957
|
-
if (
|
|
2958
|
-
else if (!v.trim()) saveSettings("global", ctx.cwd, { auditFeedbackChars: undefined });
|
|
3005
|
+
const n = Number.parseInt(v.trim(), 10);
|
|
3006
|
+
if (Number.isFinite(n) && n >= 0) saveSettings("global", ctx.cwd, { tokenLimit: n });
|
|
3007
|
+
else if (!v.trim()) saveSettings("global", ctx.cwd, { tokenLimit: undefined });
|
|
2959
3008
|
else ctx.ui.notify(`Not a non-negative integer: ${v}`, "warning");
|
|
2960
3009
|
}
|
|
3010
|
+
} else if (choice.startsWith("Reviewer config")) {
|
|
3011
|
+
await cmdReviewerSettings(ctx);
|
|
2961
3012
|
}
|
|
2962
3013
|
} catch {
|
|
2963
3014
|
return;
|
|
@@ -3161,6 +3212,8 @@ async function cmdSettings(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
3161
3212
|
fmt("aggressiveMode", "aggressiveMode"),
|
|
3162
3213
|
fmt("quotaRetryMinutes", "quotaRetryMinutes"),
|
|
3163
3214
|
fmt("stuckMaxInterventions", "stuckMaxInterventions"),
|
|
3215
|
+
fmt("stallEscalationRefires", "stallEscalation"),
|
|
3216
|
+
fmt("wedgeAlertMinutes", "wedgeAlert"),
|
|
3164
3217
|
// v0.25.6: effective per-type subagent model resolution.
|
|
3165
3218
|
...["Explore", "Plan", "general-purpose"].map(
|
|
3166
3219
|
(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.
|
|
3
|
+
"version": "0.27.1",
|
|
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",
|