feat(web): render plan review card with plan body and approach choices - #1101
Conversation
The ExitPlanMode plan_review approval in the web UI now renders the plan body as Markdown with one button per approach option, plus Revise and Reject-and-Exit, with the selected label threaded back to the server. The approval header keeps APPROVAL REQUIRED and the minimize control on the title row and shows the plan path on a second line, and the plan body uses up to half the viewport height. The ExitPlanMode tool card also gains a link to the plan file, currently hidden behind a flag until the server can read files outside the workspace.
🦋 Changeset detectedLatest commit: 269352b The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 674433f650
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| <div class="kbtn" @click="revisePlan">{{ t('approval.revise') }}<span class="k">[2]</span></div> | ||
| <div class="kbtn danger" @click="rejectAndExitPlan">{{ t('approval.rejectAndExit') }}<span class="k">[3]</span></div> |
There was a problem hiding this comment.
Avoid duplicate plan-review shortcut numbers
When a plan review has two or three approach options, the option buttons already advertise [2]/[3], and handleKeydown maps those keys to approving option 2/3 before returning. These Revise and Reject-and-Exit buttons still advertise the same shortcuts, so a user pressing the visible [2] for Revise (or [3] for Reject and Exit) instead approves an approach and lets the agent proceed with edits.
Useful? React with 👍 / 👎.
When a plan review has approach options, the option buttons already own [1]/[2]/[3]. Revise and Reject-and-Exit advertised the same numbers even though those keys approve an option, so hide their shortcut labels whenever options are present.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 269352b681
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // flushGroup settles dangling tools of finished turns back to 'ok'. | ||
| status: 'running', | ||
| output: c.outputLines, | ||
| planPath: c.toolName === 'ExitPlanMode' ? planReviewByToolCallId[c.toolCallId]?.path : undefined, |
There was a problem hiding this comment.
Preserve the reviewed plan after resolution
For ExitPlanMode approvals that are revised or rejected, the approval card is removed as soon as approvalResolved arrives, and the synthetic tool result does not include the plan body. This line only carries the preserved path into the tool card, so the stored planReviewByToolCallId[...].plan is never rendered after resolution; users lose the plan they just reviewed in the transcript in those flows. Please thread the saved plan into the ToolCall model/rendering as well, or otherwise keep the plan visible after the approval resolves.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Acknowledged. We considered rendering the preserved plan inline, but it only helps the live session: the plan body is not persisted in any message, so after a reload (and in replay) it is unavailable for the reject/revise flows regardless. The durable fix is to read the plan file via the file-preview link (already wired, hidden behind a flag), but that needs a backend API to read files outside the workspace — plan files live under the session data dir and the server readFile is workspace-scoped. Deferring inline rendering until the backend can provide the plan content reliably.
Related Issue
N/A — no prior issue; this is a small, maintainer-directed UX fix. The problem is described below.
Problem
Plan mode was effectively unusable in the web UI. When the agent calls
ExitPlanMode, theplan_reviewapproval rendered only a one-line action summary — neither the plan body nor the approach options were shown — so the user could not read the plan or choose an approach before deciding.What changed
plan_reviewapproval as a proper card: the plan body as Markdown, one approve button per approach option, plus Revise and Reject and Exit, withselectedLabelthreaded through to the server so the decision resolves correctly on the agent side.APPROVAL REQUIREDand the minimize control on the title row, show the plan file path on a second line, and let the plan body use up to half the viewport height.ExitPlanModetool card gains a link to the plan file, currently hidden behind a flag until the server can read files outside the workspace. Plan files live under the session data directory (not the cwd), and the server'sreadFileis workspace-scoped, so the preview rejects them today; the wiring is kept in place so the link can be enabled once a backend API exists.Checklist
pnpm typecheckandpnpm build.)gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update. (Self-explanatory web UI change; plan mode behavior is unchanged.)