pi-goal-list-loop-audit 0.19.0 → 0.19.2
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.
|
@@ -202,7 +202,7 @@ export function parseListImport(content: string): string[] {
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
/**
|
|
205
|
-
* During a LIST drafting session the agent must not
|
|
205
|
+
* During a LIST drafting session the agent must not add items one by one
|
|
206
206
|
* with list_add/list_activate — that bypasses the user's Confirm gate
|
|
207
207
|
* (observed in the wild: the agent decomposed a dump and ACTIVATED the first
|
|
208
208
|
* item with zero confirmation). The batch path is propose_goal_draft's
|
|
@@ -214,7 +214,7 @@ export function listMutationBlocked(draftingTarget: string | null): boolean {
|
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
export const LIST_DRAFTING_BLOCK_MESSAGE =
|
|
217
|
-
"LIST DRAFTING IN PROGRESS — do not
|
|
217
|
+
"LIST DRAFTING IN PROGRESS — do not add items one by one. Decompose the request into an items[] array and call propose_goal_draft ONCE: the user confirms the whole batch in a single dialog. list_add / list_activate work again after the drafting session ends.";
|
|
218
218
|
|
|
219
219
|
/**
|
|
220
220
|
* Route natural-language text handed to `/list` with no subcommand verb
|
|
@@ -67,7 +67,7 @@ export function buildStatusText(state: State, audit?: AuditDisplayProgress | nul
|
|
|
67
67
|
if (g.status === "active") {
|
|
68
68
|
const queue = state.list?.length ? ` · list ${state.list.length}` : "";
|
|
69
69
|
const tasks = g.taskList ? ` ${countDone(g)}/${countTotal(g)} tasks ·` : "";
|
|
70
|
-
return `glla:
|
|
70
|
+
return `glla: ${g.policy} ●${tasks} ${fmtElapsed(now - Date.parse(g.createdAt))}${queue}`;
|
|
71
71
|
}
|
|
72
72
|
return undefined; // complete/aborted → clear
|
|
73
73
|
}
|
package/extensions/loops/goal.ts
CHANGED
|
@@ -431,7 +431,7 @@ async function startDrafting(ctx: ExtensionContext, target: "goal" | "list" | "l
|
|
|
431
431
|
draftingTarget = target;
|
|
432
432
|
const prompts: Record<string, [string, string, string]> = {
|
|
433
433
|
goal: ["goal-loop-draft.md", "Goal drafting", "propose_goal_draft"],
|
|
434
|
-
list: ["goal-loop-draft.md", "Goal drafting (for the
|
|
434
|
+
list: ["goal-loop-draft.md", "Goal drafting (for the list)", "propose_goal_draft"],
|
|
435
435
|
loop: ["goal-loop-forever-draft.md", "Loop drafting", "propose_loop_draft"],
|
|
436
436
|
};
|
|
437
437
|
const [file, label, tool] = prompts[target]!;
|
|
@@ -729,7 +729,7 @@ async function cmdList(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
729
729
|
if (queue.length === 0) {
|
|
730
730
|
lines.push("List: empty. /list <describe your tasks, or a plan file> — the agent shapes dumps into items, files import directly.");
|
|
731
731
|
} else {
|
|
732
|
-
lines.push(`
|
|
732
|
+
lines.push(`List (${queue.length}):`);
|
|
733
733
|
const PAGE = 15;
|
|
734
734
|
queue.slice(0, PAGE).forEach((item, i) => lines.push(` ${i + 1}. ${item.objective.slice(0, 90)}`));
|
|
735
735
|
if (queue.length > PAGE) {
|
|
@@ -1491,7 +1491,7 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
1491
1491
|
const wasIdle = !state.goal || state.goal.status === "complete" || state.goal.status === "aborted";
|
|
1492
1492
|
const n = enqueueItems(liveCtx, p.items, "drafted batch");
|
|
1493
1493
|
if (wasIdle) {
|
|
1494
|
-
return { content: [{ type: "text", text: `${n} items confirmed; first activated (
|
|
1494
|
+
return { content: [{ type: "text", text: `${n} items confirmed; first activated (list was empty). Begin work now.` }], details: {} };
|
|
1495
1495
|
}
|
|
1496
1496
|
return { content: [{ type: "text", text: `${n} items confirmed and queued (${listQueue().length} waiting).` }], details: {} };
|
|
1497
1497
|
}
|
|
@@ -1522,7 +1522,7 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
1522
1522
|
appendLedger(liveCtx.cwd, "list_added", { id: item.id, objective: item.objective, drafted: true });
|
|
1523
1523
|
if (!state.goal || state.goal.status === "complete" || state.goal.status === "aborted") {
|
|
1524
1524
|
activateNextListItem(liveCtx);
|
|
1525
|
-
return { content: [{ type: "text", text: "Confirmed and activated (
|
|
1525
|
+
return { content: [{ type: "text", text: "Confirmed and activated (list was empty). Begin work now." }], details: {} };
|
|
1526
1526
|
}
|
|
1527
1527
|
return { content: [{ type: "text", text: `Confirmed and queued (${listQueue().length} waiting). It activates when the current goal completes.` }], details: {} };
|
|
1528
1528
|
}
|
|
@@ -1701,9 +1701,9 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
1701
1701
|
pi.registerTool(defineTool({
|
|
1702
1702
|
name: "list_add",
|
|
1703
1703
|
label: "Add to queue",
|
|
1704
|
-
description: "Add one or many objectives to the /list list (loop 2). Use when the user asks to queue work — 'add these to my list', 'queue these 10 things', 'put this on the backlog'. Each item becomes an audited goal; per-item 'Done when:' clauses are honored. The first queued item activates automatically when nothing is running.",
|
|
1704
|
+
description: "Add one or many objectives to the /list list (loop 2). Use when the user asks to queue work — 'add these to my list', 'queue these 10 things', 'put this on the backlog'. Each item becomes an audited goal; per-item 'Done when:' clauses are honored. The first queued item activates automatically when nothing is running. The list is UNBOUNDED — hundreds of small items are fine; propose them all.",
|
|
1705
1705
|
parameters: Type.Object({
|
|
1706
|
-
items: Type.Array(Type.String(), { description: "Objectives to enqueue
|
|
1706
|
+
items: Type.Array(Type.String(), { description: "Objectives to enqueue — no count limit; large plans belong in ONE call." }),
|
|
1707
1707
|
}),
|
|
1708
1708
|
async execute(_id, params, _signal, _onUpdate, execCtx) {
|
|
1709
1709
|
const p = params as { items: string[] };
|
|
@@ -1713,9 +1713,6 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
1713
1713
|
if (!Array.isArray(p.items) || p.items.length === 0) {
|
|
1714
1714
|
return { content: [{ type: "text", text: "No items given." }], details: {} };
|
|
1715
1715
|
}
|
|
1716
|
-
if (p.items.length > 100) {
|
|
1717
|
-
return { content: [{ type: "text", text: `Too many items at once (${p.items.length}); max 100 per call — batch larger plans across calls.` }], details: {} };
|
|
1718
|
-
}
|
|
1719
1716
|
const clean = p.items.map((t) => t.trim()).filter((t) => t.length > 0);
|
|
1720
1717
|
const liveCtx = (execCtx as ExtensionContext | undefined) ?? ctx;
|
|
1721
1718
|
const wasIdle = !state.goal || state.goal.status === "complete" || state.goal.status === "aborted";
|
|
@@ -1775,7 +1772,7 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
1775
1772
|
if (queue.length === 0) {
|
|
1776
1773
|
lines.push("List: empty.");
|
|
1777
1774
|
} else {
|
|
1778
|
-
lines.push(`
|
|
1775
|
+
lines.push(`List (${queue.length}):`);
|
|
1779
1776
|
queue.slice(0, 20).forEach((item, i) => lines.push(`${i + 1}. ${item.objective}`));
|
|
1780
1777
|
if (queue.length > 20) lines.push(`… and ${queue.length - 20} more`);
|
|
1781
1778
|
}
|
|
@@ -1955,20 +1952,20 @@ function resolveAuditorModel(ctx: ExtensionContext, ref?: string): { model: any;
|
|
|
1955
1952
|
}
|
|
1956
1953
|
const sessionModel = ctx.model as any;
|
|
1957
1954
|
if (sessionModel) return { model: sessionModel, via: "session" };
|
|
1958
|
-
return { model: undefined, error: "no session model and no auditorModel configured — set one with /
|
|
1955
|
+
return { model: undefined, error: "no session model and no auditorModel configured — set one with /glla model=provider/id" };
|
|
1959
1956
|
}
|
|
1960
1957
|
|
|
1961
1958
|
// (v0.9.12) The auto-fallback apparatus was REMOVED: no tier ranking, no
|
|
1962
1959
|
// candidate chains, no dead-model caches. The plugin never picks a model —
|
|
1963
|
-
// you select it in pi (session model) or in /
|
|
1960
|
+
// you select it in pi (session model) or in /glla (explicit override). When
|
|
1964
1961
|
// neither works, the failure surfaces plainly (see the three-way split in
|
|
1965
1962
|
// the complete_goal handler) with the exact fix; nothing is substituted
|
|
1966
1963
|
// silently.
|
|
1967
1964
|
|
|
1968
1965
|
/**
|
|
1969
|
-
* The /
|
|
1966
|
+
* The /glla interactive settings UI (v0.8.0): a menu loop over pi's dialog
|
|
1970
1967
|
* primitives. Pick a setting → edit it → saved to GLOBAL → back to the menu.
|
|
1971
|
-
* Done/Esc exits. Rarely opened by design; scriptable /
|
|
1968
|
+
* Done/Esc exits. Rarely opened by design; scriptable /glla key=value remains
|
|
1972
1969
|
* for tmux/headless.
|
|
1973
1970
|
*/
|
|
1974
1971
|
async function openSettingsUI(ctx: ExtensionContext): Promise<void> {
|
|
@@ -2022,13 +2019,13 @@ async function openSettingsUI(ctx: ExtensionContext): Promise<void> {
|
|
|
2022
2019
|
|
|
2023
2020
|
async function cmdSettings(args: string, ctx: ExtensionContext): Promise<void> {
|
|
2024
2021
|
// The plugin's ONE config surface — global by default, rarely opened.
|
|
2025
|
-
// /
|
|
2026
|
-
// /
|
|
2027
|
-
// /
|
|
2028
|
-
// /
|
|
2029
|
-
// /
|
|
2030
|
-
// /
|
|
2031
|
-
// /
|
|
2022
|
+
// /glla show effective values + where each comes from
|
|
2023
|
+
// /glla model=provider/id write to GLOBAL config
|
|
2024
|
+
// /glla thinking=high write to GLOBAL config
|
|
2025
|
+
// /glla notify='cmd $1' write to GLOBAL config
|
|
2026
|
+
// /glla tokenlimit=2000000 write to GLOBAL config
|
|
2027
|
+
// /glla project model=... write to PROJECT override (rare)
|
|
2028
|
+
// /glla model=unset remove key (from global; project model=unset for project)
|
|
2032
2029
|
const trimmed = args.trim();
|
|
2033
2030
|
if (!trimmed) {
|
|
2034
2031
|
if (ctx.hasUI) {
|
|
@@ -2050,7 +2047,7 @@ async function cmdSettings(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
2050
2047
|
fmt("tokenLimit", "tokenLimit"),
|
|
2051
2048
|
`\nglobal: ${globalSettingsPath()}`,
|
|
2052
2049
|
`project: ${projectSettingsPath(ctx.cwd)}`,
|
|
2053
|
-
`Set with: /
|
|
2050
|
+
`Set with: /glla key=value (global) · /glla project key=value (project override)`,
|
|
2054
2051
|
].join("\n"),
|
|
2055
2052
|
"info",
|
|
2056
2053
|
);
|
|
@@ -2140,7 +2137,7 @@ function warnIfAuditorProviderRisky(ctx: ExtensionContext): void {
|
|
|
2140
2137
|
const provider = (ctx.model as any)?.provider as string | undefined;
|
|
2141
2138
|
if (!provider || KNOWN_BUILTIN_PROVIDERS.has(provider)) return;
|
|
2142
2139
|
ctx.ui.notify(
|
|
2143
|
-
`pi-goal-list-loop-audit: session provider "${provider}" is extension-registered — the auditor (extension-less session) will fail auth with it. If audits error, set a built-in override once: /
|
|
2140
|
+
`pi-goal-list-loop-audit: session provider "${provider}" is extension-registered — the auditor (extension-less session) will fail auth with it. If audits error, set a built-in override once: /glla model=provider/id`,
|
|
2144
2141
|
"info",
|
|
2145
2142
|
);
|
|
2146
2143
|
} catch {
|
|
@@ -2185,7 +2182,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
2185
2182
|
// /goal — set/draft + status|pause|resume|cancel|tweak|archive subcommands
|
|
2186
2183
|
// /list — the list (add|show|next|remove|clear)
|
|
2187
2184
|
// /loop — the metric loop (draft|start|status|stop)
|
|
2188
|
-
// /
|
|
2185
|
+
// /glla — the settings UI (+ scriptable key=value)
|
|
2189
2186
|
pi.registerCommand("goal", {
|
|
2190
2187
|
description: "Set/draft a goal, or /goal status|pause|resume|cancel|tweak <text>|archive|start <objective>. Objectives without a 'Done when:' clause are grilled into a contract first; include the clause or use /goal start to skip the interview and activate instantly.",
|
|
2191
2188
|
handler: (args: string, ctx: ExtensionContext) => { rememberCtx(ctx); return cmdGoal(args, ctx); },
|
|
@@ -2314,7 +2311,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
2314
2311
|
|
|
2315
2312
|
// Token accounting + cost guard: accumulate this turn's assistant tokens
|
|
2316
2313
|
// (deduped — agent_end may replay seen messages). Crossing the goal's
|
|
2317
|
-
// token limit pauses it; /
|
|
2314
|
+
// token limit pauses it; /glla tokenlimit=<n> to raise.
|
|
2318
2315
|
const newTokens = sumNewAssistantTokens(event.messages as unknown[], countedTokenMessages);
|
|
2319
2316
|
if (newTokens > 0) {
|
|
2320
2317
|
const used = (state.goal.usage?.tokensUsed ?? 0) + newTokens;
|
|
@@ -2325,9 +2322,9 @@ export default function (pi: ExtensionAPI): void {
|
|
|
2325
2322
|
usage: { tokensUsed: used, tokensLimit: limit },
|
|
2326
2323
|
status: "paused",
|
|
2327
2324
|
pauseReason: `token limit exceeded (${used.toLocaleString()} > ${limit.toLocaleString()})`,
|
|
2328
|
-
pauseSuggestedAction: "/
|
|
2325
|
+
pauseSuggestedAction: "/glla tokenlimit=<n> to raise the cap (or 0 to disable), then /goal resume",
|
|
2329
2326
|
}, ctx);
|
|
2330
|
-
ctx.ui.notify(`Goal paused: token limit exceeded (${used.toLocaleString()} > ${limit.toLocaleString()}). /
|
|
2327
|
+
ctx.ui.notify(`Goal paused: token limit exceeded (${used.toLocaleString()} > ${limit.toLocaleString()}). /glla tokenlimit=<n> to raise, 0 to disable.`, "warning");
|
|
2331
2328
|
notifyExternal(ctx, `Goal paused: token limit exceeded (${used} > ${limit}).`);
|
|
2332
2329
|
return;
|
|
2333
2330
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.2",
|
|
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",
|