pi-goal-list-loop-audit 0.27.0 → 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.
|
@@ -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
|
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.27.
|
|
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",
|