From f2f9e6a1b9d2149ae01a384b0eab8e419ddb0aa4 Mon Sep 17 00:00:00 2001 From: wassname Date: Mon, 15 Jun 2026 20:49:57 +0800 Subject: [PATCH] pi-plan: finish stale-pi crash fix, print plan on start, todo->task - The Ready->fresh-context crash was a stale pi.* call inside withSession. Prior commit moved sendUserMessage to sessionCtx but left pi.setSessionName inside withSession (also stale -> crash). Drop it (cosmetic) and use only sessionCtx in the swap window. - Print plan.md on execution start (both fresh and in-place) so the user sees what's being worked on after a context switch. Plan text captured before newSession since ctx goes stale. - Widget: "(N todo)" -> "(N task[s])" Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com> --- src/index.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 8514128..ec62b81 100644 --- a/src/index.ts +++ b/src/index.ts @@ -77,7 +77,7 @@ export default function piPlanExtension(pi: ExtensionAPI): void { for (const g of doc.goals) { if (g.status === "done") continue; // hide finished goals; they stay in the file const open = g.subtasks.filter((s) => !s.done).length; - lines.push(`${mark[g.status]} ${g.subject}${open ? ` (${open} todo)` : ""}`); + lines.push(`${mark[g.status]} ${g.subject}${open ? ` (${open} task${open === 1 ? "" : "s"})` : ""}`); } const c = counts(doc); if (c.done) lines.push(`(${c.done} done, hidden)`); @@ -201,17 +201,20 @@ export default function piPlanExtension(pi: ExtensionAPI): void { } const doc = parse(readPlan(ctx)); const planFile = planPath(ctx); + const planContent = readPlan(ctx); // captured now: ctx is stale after newSession below const parentSession = ctx.sessionManager.getSessionFile(); const startMsg = `Work the plan in ${planFile}. Pick an open goal, set it active, work its subtasks, and when its done_when is met call CompleteGoal with the evidence. Keep plan.md current as you go.`; exitPlanMode(ctx); if (fresh && savedCmdCtx) { - // After newSession, `ctx`/`pi` bound to the old session are stale — do post-swap work + // After newSession, `ctx`/`pi` bound to the old session are stale; do post-swap work // through the ReplacedSessionContext passed to withSession (see runner.assertActive). const result = await savedCmdCtx.newSession({ parentSession, withSession: async (sessionCtx) => { - if (doc.objective) pi.setSessionName(`Plan: ${doc.objective}`); + // pi.* and the outer ctx are invalidated by newSession; use the fresh sessionCtx only. + // (No setSessionName here: it lives on pi/the outer ctx, both stale now. Cosmetic, skip it.) + sessionCtx.ui.notify(planContent, "info"); await sessionCtx.sendUserMessage(startMsg, { deliverAs: "followUp" }); }, }); @@ -221,6 +224,7 @@ export default function piPlanExtension(pi: ExtensionAPI): void { return; } if (doc.objective) pi.setSessionName(`Plan: ${doc.objective}`); + ctx.ui.notify(planContent, "info"); pi.sendUserMessage(startMsg, { deliverAs: "followUp" }); }