pi-goal-list-loop-audit 0.24.3 → 0.24.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/README.md +1 -1
- package/extensions/goal-loop-forever.ts +10 -4
- package/extensions/loops/goal.ts +29 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ matches `/list show`.
|
|
|
60
60
|
/list cancel # stop the whole list: abort the active item + drop all waiting
|
|
61
61
|
/loop # draft the loop (agent grills; measure is test-run before you confirm)
|
|
62
62
|
/loop start "keep polishing the UI" # infinite metricless loop (v0.23.6): no plateau, no cap — ends at time=/tokens= or /loop stop
|
|
63
|
-
/loop respec # infinite metricless loop reconciling the codebase against the root SPEC.md / spec.md (v0.24.3)
|
|
63
|
+
/loop respec # infinite metricless loop reconciling the codebase against the root SPEC.md / spec.md (v0.24.3) — 2 specs = you pick, 0 specs = drafting, 1 spec = auto-start (v0.24.4)
|
|
64
64
|
/loop start "reduce TODOs" measure="grep -c TODO src.txt | head -1" direction=min
|
|
65
65
|
/loop start "shrink the bundle" measure="..." direction=min time=4 tokens=500000 # arbitrary bounds
|
|
66
66
|
/loop start "reduce TODOs" measure="..." direction=min branch=1 # scratch-branch mode
|
|
@@ -302,15 +302,21 @@ export function parseLoopStartArgs(raw: string): {
|
|
|
302
302
|
/** Root-only spec candidates, in priority order. No fuzzy search. */
|
|
303
303
|
export const RESPEC_SPEC_CANDIDATES = ["SPEC.md", "spec.md"] as const;
|
|
304
304
|
|
|
305
|
-
/** Resolve
|
|
306
|
-
export function
|
|
305
|
+
/** Resolve every root spec candidate that exists (priority order). */
|
|
306
|
+
export function resolveSpecFiles(cwd: string): string[] {
|
|
307
|
+
const found: string[] = [];
|
|
307
308
|
for (const name of RESPEC_SPEC_CANDIDATES) {
|
|
308
309
|
const p = join(cwd, name);
|
|
309
310
|
try {
|
|
310
|
-
if (existsSync(p) && statSync(p).isFile())
|
|
311
|
+
if (existsSync(p) && statSync(p).isFile()) found.push(p);
|
|
311
312
|
} catch { /* unreadable — keep looking */ }
|
|
312
313
|
}
|
|
313
|
-
return
|
|
314
|
+
return found;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/** Resolve the project spec in the root only; null when absent. */
|
|
318
|
+
export function resolveSpecFile(cwd: string): string | null {
|
|
319
|
+
return resolveSpecFiles(cwd)[0] ?? null;
|
|
314
320
|
}
|
|
315
321
|
|
|
316
322
|
/**
|
package/extensions/loops/goal.ts
CHANGED
|
@@ -82,8 +82,7 @@ import {
|
|
|
82
82
|
parseLoopStartArgs,
|
|
83
83
|
parseMetric,
|
|
84
84
|
LOOP_DEFAULTS,
|
|
85
|
-
|
|
86
|
-
resolveSpecFile,
|
|
85
|
+
resolveSpecFiles,
|
|
87
86
|
respecTarget,
|
|
88
87
|
type LoopState,
|
|
89
88
|
} from "../goal-loop-forever.js";
|
|
@@ -1425,14 +1424,37 @@ async function cmdLoop(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
1425
1424
|
ctx.ui.notify("A loop is already active. /loop stop first.", "warning");
|
|
1426
1425
|
return;
|
|
1427
1426
|
}
|
|
1428
|
-
const
|
|
1429
|
-
if (
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1427
|
+
const specs = resolveSpecFiles(ctx.cwd);
|
|
1428
|
+
if (specs.length === 0) {
|
|
1429
|
+
// No spec → the target is undetermined; grill instead of dead-ending
|
|
1430
|
+
// on an error (v0.24.4).
|
|
1431
|
+
ctx.ui.notify("No SPEC.md / spec.md in the project root — drafting the loop target with you (or bootstrap a spec first).", "info");
|
|
1432
|
+
await startDrafting(
|
|
1433
|
+
ctx,
|
|
1434
|
+
"loop",
|
|
1435
|
+
"reconcile the codebase against the project spec — but NO SPEC.md / spec.md exists in the root. Grill the user: should the first work be bootstrapping a SPEC.md from the current code (then reconcile against it), or is the reconciliation target better stated in prose? Challenge vague answers.",
|
|
1433
1436
|
);
|
|
1434
1437
|
return;
|
|
1435
1438
|
}
|
|
1439
|
+
let specPath = specs[0]!;
|
|
1440
|
+
if (specs.length > 1) {
|
|
1441
|
+
// Two specs = ambiguous — never silently pick (v0.24.4). One
|
|
1442
|
+
// slash-bar select, plus a nudge to consolidate.
|
|
1443
|
+
const names = specs.map((p) => path.basename(p));
|
|
1444
|
+
const choice = await ctx.ui.select(
|
|
1445
|
+
"Both SPEC.md and spec.md exist in the root — which one is the spec?",
|
|
1446
|
+
names,
|
|
1447
|
+
);
|
|
1448
|
+
if (choice === undefined) {
|
|
1449
|
+
ctx.ui.notify("respec cancelled.", "info");
|
|
1450
|
+
return;
|
|
1451
|
+
}
|
|
1452
|
+
specPath = specs[names.indexOf(choice)]!;
|
|
1453
|
+
ctx.ui.notify(
|
|
1454
|
+
`Using ${path.basename(specPath)} as the spec. Both files exist — worth consolidating; the loop treats only ${path.basename(specPath)} as the spec.`,
|
|
1455
|
+
"info",
|
|
1456
|
+
);
|
|
1457
|
+
}
|
|
1436
1458
|
const target = respecTarget(path.basename(specPath));
|
|
1437
1459
|
await startLoopFromConfig(ctx, {
|
|
1438
1460
|
target,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.4",
|
|
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",
|