pi-gauntlet 8.1.3 → 8.1.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## v8.1.4 - 2026-11-01
4
+
5
+ - Ledger task labels compact criterion descriptions to at most 80 characters at a word boundary with `...` when shortened, preserving attempts prefixes, repository owners and short criteria.
6
+
3
7
  ## v8.1.3 - 2026-11-01
4
8
 
5
9
  - The loop engine runs on one per-row budget: a fresh ledger carries `allowance: <maxIterationsPerRow>` (default 4) in place of `cap:`, a `4; allowance N` or `5; allowance N` approval reply overrides the setting, and each `retry <n> | <hint>` decision adds one attempt to that row. The driver drops funded rounds, `cap +N`, the total-iteration cap and amend-gated escalation; a row's last allowed attempt runs once on `escalationLoop.implModel` under option 4 and option 5 alike, and exit-verification failure gets one escalated repair per flow. Human stops offer only `retry <n> | <hint>` and `rows +N` and print each open row as `<attempts> of <allowance>`; the task tracker labels rows `<attempts>/<allowance>: <criterion text>` while task names stay `row N`. A legacy `cap:` ledger migrates on resume through a parent `loop: migrate allowance` commit. (#108)
@@ -517,6 +517,29 @@ test("allowance labels count retry decisions, preserve identity and render on ev
517
517
  descriptions.map((description, i) => `${description} (${[2, 4].includes(i) ? "repo-b" : "repo-a"})`));
518
518
  });
519
519
 
520
+ test("refresh compacts long criteria while preserving budgets, owners and short criteria", async () => {
521
+ const dir = ledgerFixture("plan-compact-labels-");
522
+ const path = join(dir, "ledger.md");
523
+ const compact = "Verify that refreshed ledger labels keep complete words within the";
524
+ const long = `${compact} description budget while retaining attempts and repository ownership`;
525
+ writeFileSync(join(dir, "spec.md"), spec([long, descriptions[1]]));
526
+ for (const mapped of [false, true]) {
527
+ const owner = mapped ? " (repo-a)" : "";
528
+ writeFileSync(path, ledger(["1 | open | 2 | check", "2 | open | 0 |"], mapped
529
+ ? "## Leg mapping\n| row | ac | leg |\n|---|---|---|\n| 1 | 1 | repo-a |\n| 2 | 2 | repo-a |" : "", "allowance: 4"));
530
+ const h = harness([], dir);
531
+ const result = await h.call({ action: "refresh", path });
532
+ assert.equal(result.details.error, undefined);
533
+ assert.deepEqual(result.details.tasks, [
534
+ { name: `row 1${owner}`, status: "pending", label: `2/4: ${compact}...${owner}` },
535
+ { name: `row 2${owner}`, status: "pending", label: `0/4: ${descriptions[1]}${owner}` },
536
+ ]);
537
+ assert.ok(`${compact}...`.length <= 80);
538
+ assert.ok(h.widget()!.endsWith(`2/4: ${compact}...${owner}`));
539
+ assert.ok(result.content[0].text.includes(`row 1${owner} | 2/4: ${compact}...${owner}`));
540
+ }
541
+ });
542
+
520
543
  test("allowance labels tolerate surrounding whitespace in the header value", async () => {
521
544
  const dir = ledgerFixture("plan-allowance-whitespace-");
522
545
  const path = join(dir, "ledger.md");
@@ -75,6 +75,12 @@ function criterionDescriptions(spec: string): string[] {
75
75
  return descriptions.map(text => text.replace(/\s+/g, " ").trim());
76
76
  }
77
77
 
78
+ function compactDescription(description: string): string {
79
+ if (description.length <= 80) return description;
80
+ const boundary = description.lastIndexOf(" ", 77);
81
+ return `${description.slice(0, Math.max(0, boundary))}...`;
82
+ }
83
+
78
84
  function ledgerTasks(text: string, path: string): Task[] {
79
85
  const lines = text.split("\n");
80
86
  if (lines[0] !== "# Ledger - loop engine") {
@@ -152,7 +158,7 @@ function ledgerTasks(text: string, path: string): Task[] {
152
158
  const owner = repo === undefined ? "" : ` (${repo})`;
153
159
  const budget = allowance !== undefined && value.status !== "cut" && (value.status !== "done" || value.attempts > 0)
154
160
  ? `${value.attempts}/${allowance + (retries.get(row) ?? 0)}: ` : "";
155
- return { name: `row ${row}${owner}`, status: status(row), label: `${budget}${description}${owner}` };
161
+ return { name: `row ${row}${owner}`, status: status(row), label: `${budget}${compactDescription(description)}${owner}` };
156
162
  });
157
163
  }
158
164
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "8.1.3",
3
+ "version": "8.1.4",
4
4
  "description": "Opinionated, gated workflow skills, subagent personas, and runtime extensions for the pi coding agent.",
5
5
  "author": "Jacek Juraszek",
6
6
  "type": "module",