pi-goal-list-loop-audit 0.24.2 → 0.24.3
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 -0
- package/extensions/goal-loop-forever.ts +30 -0
- package/extensions/loops/goal.ts +41 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -60,6 +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
64
|
/loop start "reduce TODOs" measure="grep -c TODO src.txt | head -1" direction=min
|
|
64
65
|
/loop start "shrink the bundle" measure="..." direction=min time=4 tokens=500000 # arbitrary bounds
|
|
65
66
|
/loop start "reduce TODOs" measure="..." direction=min branch=1 # scratch-branch mode
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
* self-reports progress.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import { existsSync, statSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
|
|
13
16
|
export type LoopDirection = "min" | "max";
|
|
14
17
|
|
|
15
18
|
export interface LoopMeasure {
|
|
@@ -293,3 +296,30 @@ export function parseLoopStartArgs(raw: string): {
|
|
|
293
296
|
tokenBudget: Number.isFinite(tokensRaw) && tokensRaw > 0 ? tokensRaw : undefined,
|
|
294
297
|
};
|
|
295
298
|
}
|
|
299
|
+
|
|
300
|
+
// ---- /loop respec (v0.24.3) ----
|
|
301
|
+
|
|
302
|
+
/** Root-only spec candidates, in priority order. No fuzzy search. */
|
|
303
|
+
export const RESPEC_SPEC_CANDIDATES = ["SPEC.md", "spec.md"] as const;
|
|
304
|
+
|
|
305
|
+
/** Resolve the project spec in the root only; null when absent. */
|
|
306
|
+
export function resolveSpecFile(cwd: string): string | null {
|
|
307
|
+
for (const name of RESPEC_SPEC_CANDIDATES) {
|
|
308
|
+
const p = join(cwd, name);
|
|
309
|
+
try {
|
|
310
|
+
if (existsSync(p) && statSync(p).isFile()) return p;
|
|
311
|
+
} catch { /* unreadable — keep looking */ }
|
|
312
|
+
}
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* The respec target. The spec is DATA, not gospel: the loop reconciles code
|
|
318
|
+
* against it but reports stale/contradictory requirements instead of forcing
|
|
319
|
+
* the code to match a bad spec. Rotation keeps it honest: implement one
|
|
320
|
+
* iteration, audit the next (the doorknob failure is implementing nothing
|
|
321
|
+
* while claiming polish).
|
|
322
|
+
*/
|
|
323
|
+
export function respecTarget(specName: string): string {
|
|
324
|
+
return `Reconcile the codebase against ${specName} (the project spec in the root). Read the spec critically first: if a requirement is stale, contradictory, or wrong for the current codebase, report the discrepancy and move on — never force the code to match a bad spec. Otherwise pick the next gap between spec and code and close it. Rotate: one iteration implements a missing or outdated spec item, the next audits something already "implemented" against the spec and fixes what drifted.`;
|
|
325
|
+
}
|
package/extensions/loops/goal.ts
CHANGED
|
@@ -81,6 +81,10 @@ import {
|
|
|
81
81
|
loopBranchName,
|
|
82
82
|
parseLoopStartArgs,
|
|
83
83
|
parseMetric,
|
|
84
|
+
LOOP_DEFAULTS,
|
|
85
|
+
RESPEC_SPEC_CANDIDATES,
|
|
86
|
+
resolveSpecFile,
|
|
87
|
+
respecTarget,
|
|
84
88
|
type LoopState,
|
|
85
89
|
} from "../goal-loop-forever.js";
|
|
86
90
|
import {
|
|
@@ -1408,6 +1412,40 @@ async function cmdLoop(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
1408
1412
|
return;
|
|
1409
1413
|
}
|
|
1410
1414
|
|
|
1415
|
+
if (sub === "respec") {
|
|
1416
|
+
// v0.24.3: reconcile the codebase against the root spec, forever.
|
|
1417
|
+
// Same auto-start path as /loop start (the user typed the command —
|
|
1418
|
+
// that IS the act); metricless + unbounded by design. No limit-nagging:
|
|
1419
|
+
// bounds exist on /loop start for whoever wants them.
|
|
1420
|
+
if (state.goal && state.goal.status === "active") {
|
|
1421
|
+
ctx.ui.notify("A goal is active — /goal cancel or /goal pause it before starting a loop.", "warning");
|
|
1422
|
+
return;
|
|
1423
|
+
}
|
|
1424
|
+
if (isLoopActive()) {
|
|
1425
|
+
ctx.ui.notify("A loop is already active. /loop stop first.", "warning");
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
const specPath = resolveSpecFile(ctx.cwd);
|
|
1429
|
+
if (!specPath) {
|
|
1430
|
+
ctx.ui.notify(
|
|
1431
|
+
`/loop respec: no spec in the project root (looked for ${RESPEC_SPEC_CANDIDATES.join(", ")}). Create one, or use /loop start "<target>" directly.`,
|
|
1432
|
+
"warning",
|
|
1433
|
+
);
|
|
1434
|
+
return;
|
|
1435
|
+
}
|
|
1436
|
+
const target = respecTarget(path.basename(specPath));
|
|
1437
|
+
await startLoopFromConfig(ctx, {
|
|
1438
|
+
target,
|
|
1439
|
+
measureCmd: "",
|
|
1440
|
+
direction: undefined,
|
|
1441
|
+
plateauWindow: LOOP_DEFAULTS.plateauWindow,
|
|
1442
|
+
maxIterations: 0,
|
|
1443
|
+
branch: false,
|
|
1444
|
+
force: false,
|
|
1445
|
+
});
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1411
1449
|
// Anything else is a natural-language target (v0.22.4): draft it — the
|
|
1412
1450
|
// metric is the whole game for a loop, and /loop start with full params
|
|
1413
1451
|
// is the skip-drafting path. Previously this fell through to a usage
|
|
@@ -1868,7 +1906,7 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
1868
1906
|
const p = params as { target: string; measureCmd?: string; direction?: "min" | "max"; window?: number; max?: number; time?: number; tokens?: number; branch?: boolean };
|
|
1869
1907
|
if (draftingTarget !== "loop") {
|
|
1870
1908
|
return {
|
|
1871
|
-
content: [{ type: "text", text: "
|
|
1909
|
+
content: [{ type: "text", text: "You cannot start or draft a loop — only the user can, from the slash bar (the Confirm is the product). Do NOT write draft files or wait for the user to say 'start' in chat; that dead-ends. Instead hand the user the exact command: /loop start \"<target>\" (bare = infinite metricless; add measure=\"<cmd>\" direction=min|max for a metric loop), or /loop respec to reconcile against the root spec, or /loop with no args to draft interactively." }],
|
|
1872
1910
|
details: {},
|
|
1873
1911
|
};
|
|
1874
1912
|
}
|
|
@@ -2654,9 +2692,10 @@ export default function (pi: ExtensionAPI): void {
|
|
|
2654
2692
|
handler: (args: string, ctx: ExtensionContext) => { rememberCtx(ctx); return cmdList(args, ctx); },
|
|
2655
2693
|
});
|
|
2656
2694
|
pi.registerCommand("loop", {
|
|
2657
|
-
description: "Loop 3: metric-driven process — it never completes. /loop <target> drafts the metric with you · /loop start \"<target>\" = infinite metricless loop (no plateau, no cap; ends at time=/tokens= or /loop stop) · add measure=\"<cmd>\" direction=min|max [window=5] [max=50] [branch=1] for a metric loop · /loop status · /loop stop. 'Improve until X' is a /goal, not a loop.",
|
|
2695
|
+
description: "Loop 3: metric-driven process — it never completes. /loop <target> drafts the metric with you · /loop start \"<target>\" = infinite metricless loop (no plateau, no cap; ends at time=/tokens= or /loop stop) · /loop respec = infinite metricless reconcile against the root SPEC.md · add measure=\"<cmd>\" direction=min|max [window=5] [max=50] [branch=1] for a metric loop · /loop status · /loop stop. 'Improve until X' is a /goal, not a loop.",
|
|
2658
2696
|
getArgumentCompletions: completions([
|
|
2659
2697
|
["start", "skip drafting: /loop start \"<target>\" measure=\"<cmd>\" direction=min|max [window=5] [max=50]"],
|
|
2698
|
+
["respec", "infinite metricless loop reconciling the codebase against the root SPEC.md"],
|
|
2660
2699
|
["status", "show metric, iteration, best/last values, stall count"],
|
|
2661
2700
|
["stop", "end the loop (keeps the best state)"],
|
|
2662
2701
|
]),
|
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.3",
|
|
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",
|