From 3a1afd4c8e75e8423bfc410215628514bcfb6880 Mon Sep 17 00:00:00 2001 From: wassname Date: Fri, 21 Aug 2026 08:14:29 +0800 Subject: [PATCH] ready menu: print the plan, add "Ready + compact" "Ready?" over an unread file is not a review -- the only copy of the plan was inside a collapsed edit tool call. Print the working set before the menu. The 4th option compacts the planning conversation before the work turn starts. session_compact already re-sends the whole plan file, so the exploration is summarized away and the agreed goals are not. Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com> --- README.md | 6 ++++-- src/index.ts | 33 +++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d5f454e..d18482d 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,10 @@ pi -e ./src/index.ts 1. Plan. The agent explores read-only (edit/write are blocked except on the plan file itself), asks about anything unclear, and drafts the goals into this session's plan file. The drafting rules are sent once, with your objective, not re-sent every turn. -2. Review. Read the file; a menu asks Ready, open in `$EDITOR`, or keep planning. To revise, just - reply. Plan mode ends when you pick Ready. +2. Review. The working set is printed in the transcript, then a menu asks Ready, Ready + compact, + open in `$EDITOR`, or keep planning. To revise, just reply. Plan mode ends when you pick a Ready. + Ready + compact summarizes the planning conversation away first; the plan file comes back whole + on the next turn, so nothing you agreed is lost. 3. Work. The agent ticks subtasks, appends to `## Log` and `## Learnings`, fills `evidence:`, and calls `CompleteGoal` when a discriminator is satisfied. If it leaves the plan untouched for two turns, the working set is sent back with a short upkeep reminder. diff --git a/src/index.ts b/src/index.ts index 7dfcd55..7cc319b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -258,13 +258,22 @@ export default function piGoalsExtension(pi: ExtensionAPI): void { } }); - // After a plan-mode turn: if goals were drafted, offer Ready. The human reads the file and says - // go, edits it in $EDITOR, or keeps talking to revise it (menu shape borrowed from pi-plan). + // After a plan-mode turn: if goals were drafted, print the working set and offer Ready. The plan + // is printed because "Ready?" over an unread file is not a review: the only other copy is inside + // a collapsed edit tool call. Reprinted after an $EDITOR pass only if the text changed. + // The human then says go, edits it, or keeps talking to revise it (menu shape borrowed from pi-plan). pi.on("agent_end", async (_event, ctx) => { if (!state.isPlanMode || !ctx.hasUI) return; + let printed = ""; while (scanGoals(readPlan(ctx)).length > 0) { + const working = foldPlan(readPlan(ctx)); + if (working !== printed) { + printed = working; + pi.sendMessage({ customType: "plan", content: working, display: true }); + } const choice = await ctx.ui.select(`Plan drafted in ${planRel(ctx)}. Ready?`, [ "Ready — start working the plan", + "Ready + compact — the same, but summarize the planning chatter away first", "Open in $EDITOR — edit it myself", "Keep planning (reply to revise)", ]); @@ -276,10 +285,22 @@ export default function piGoalsExtension(pi: ExtensionAPI): void { state = { ...state, isPlanMode: false }; persist(); updateWidget(ctx); - pi.sendUserMessage( - `Work the goals in ${planPath(ctx)}. Pick an open goal, mark it active ([/]), work its subtasks, and when its discriminator is satisfied fill its evidence: list, then call CompleteGoal with the goal's text. Keep the plan file current as you go.`, - { deliverAs: "followUp" }, - ); + const work = `Work the goals in ${planPath(ctx)}. Pick an open goal, mark it active ([/]), work its subtasks, and when its discriminator is satisfied fill its evidence: list, then call CompleteGoal with the goal's text. Keep the plan file current as you go.`; + if (!choice.includes("compact")) { + pi.sendUserMessage(work, { deliverAs: "followUp" }); + return; + } + // Compaction fires session_compact, so the whole plan file comes back on the next call -- + // the exploration is summarized away, the agreed goals are not. Sent from onComplete so + // the work turn starts after the summary exists; a failed compaction still starts work. + ctx.compact({ + customInstructions: `Planning is finished. Keep what ${planRel(ctx)} depends on: the objective, the human's constraints, and what was ruled out and why. The read-only exploration that produced them can go.`, + onComplete: () => pi.sendUserMessage(work, { deliverAs: "followUp" }), + onError: (e) => { + ctx.ui.notify(`Compaction failed (${e.message}); starting work anyway.`, "warning"); + pi.sendUserMessage(work, { deliverAs: "followUp" }); + }, + }); return; } });