feat(plan-mode): Persist plans as markdown and fix approval UX#461
Merged
feat(plan-mode): Persist plans as markdown and fix approval UX#461
Conversation
Closes #434. The RequestPlanApproval tool now writes the plan to <configDir>/plans/<timestamp>-<slug>.md (atomic .tmp + rename) and reads the file back as the canonical plan content. The default plan-mode system prompt requires the plan body to use a fixed 8-section H2 template (Context, Files to Modify, Current Code, Changes, Performance Impact, Critical Files, Edge Cases, Verification). Several existing plan-mode bugs surfaced by end-to-end testing are also fixed in this branch: - Reasoning_content was dropped on the post-approval continuation, triggering a 400 from DeepSeek's thinking mode. The synthesized IsPlan assistant message duplicated the tool-call args without reasoning, so it's now filtered from the request via a new buildAgentMessagesFromEntries helper. - A race between publishPlanApprovalRequest and MarkLastMessageAsPlan could mark the LLM's preamble turn as IsPlan, causing the wrong content to render under "Plan (Pending Approval):". Event publication now happens inside createPlanMessage, after the IsPlan entry is added; the redundant MarkLastMessageAsPlan call was removed. - Plan-approval button navigation (left/right) updated state but didn't trigger a re-render, so the highlighted button never moved. A new PlanApprovalSelectionChangedEvent now drives the viewport refresh. - Up/down arrows during plan approval triggered history navigation; they're now disabled while plan or tool approval is pending. - renderPlanEntry put role + body on one line and produced an effectively-empty body. It now mirrors renderShortcutOutput so the full markdown plan is visible above the buttons. Adds docs/plan-mode.md, a RequestPlanApproval entry in docs/tools-reference.md, and a CLAUDE.md section pointing to them. Adds plans/ to .infer/.gitignore (project + the embedded copy in cmd/init.go) so persisted plans don't leak into commits.
Contributor
|
🎉 This PR is included in version 0.105.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
RequestPlanApprovalnow writes the plan to<configDir>/plans/<timestamp>-<slug>.md(atomic write) and reads it back as canonical content; the default plan-mode prompt mandates an 8-section H2 template (Context, Files to Modify, Current Code, Changes, Performance Impact, Critical Files, Edge Cases, Verification).reasoning_contenton the post-approval turn (DeepSeek 400); race that marked the wrong assistant message asIsPlan; approval-button navigation didn't refresh the viewport; up/down arrow triggered history navigation while approval was pending; the plan body was rendered with an empty visible region above the buttons.docs/plan-mode.md, aRequestPlanApprovalentry indocs/tools-reference.md, and aCLAUDE.mdpointer; addsplans/to.infer/.gitignore(project +cmd/init.goembedded copy).