100 lines
4.6 KiB
Markdown
100 lines
4.6 KiB
Markdown
# Terminal-style review controls
|
||
|
||
**Date:** 2026-06-05
|
||
**Status:** Approved (design)
|
||
|
||
## Problem
|
||
|
||
Review feedback today is a multi-line `TextBox` plus four buttons (Approve / Reject /
|
||
Park / Cancel) tucked into the WorkConsole **Session** tab
|
||
(`WorkConsole.axaml:169-193`). It feels disconnected from the live terminal. Entering
|
||
feedback should feel like typing into the terminal, with action buttons docked at the
|
||
bottom — and merge/approve actions should live in an obvious, dedicated place.
|
||
|
||
## Goal
|
||
|
||
- Type review feedback directly in the **Output (terminal)** tab, prompt-style.
|
||
- Bottom-docked action strip on the terminal: `[Retry]` `[Reset]`.
|
||
- Move all git/merge/worktree actions (including **Approve**) into a new **Git** tab so
|
||
it is obvious where each action lives.
|
||
|
||
## Tab structure
|
||
|
||
Three tabs in WorkConsole: **Output** · **Git** · **Session**.
|
||
|
||
| Tab | Contents |
|
||
| --- | --- |
|
||
| **Output** | Live `Log` (unchanged) + new review footer (below), footer gated on `IsWaitingForReview`. |
|
||
| **Git** | The current "Merge & worktree" block — merge-target dropdown, mergeability indicator, **Approve**, Open Diff, Merge, Worktree, Review Combined Diff, Merge All Subtasks. Visibility gated on `ShowMergeSection` / `IsWaitingForReview` as today. |
|
||
| **Session** | Child outcomes + empty-state only. |
|
||
|
||
### ViewModel changes (`DetailsIslandViewModel`)
|
||
|
||
- Add `public bool IsGitTab => SelectedTab == "git";`
|
||
- Add `[NotifyPropertyChangedFor(nameof(IsGitTab))]` alongside the existing
|
||
`IsOutputTab` / `IsSessionTab` notifications on `SelectedTab` (`:139-144`).
|
||
- `SelectTab` already accepts a string parameter — no change beyond the new `"git"`
|
||
value wired from XAML.
|
||
- No command renames (avoids breaking hand-rolled test fakes).
|
||
|
||
## Terminal footer (Output tab)
|
||
|
||
A `Border` docked `Bottom` inside the Output tab body, visible only when
|
||
`IsWaitingForReview`:
|
||
|
||
- Background `Surface2Brush`, top border `LineBrush` (`BorderThickness="0,1,0,0"`).
|
||
- A `❯` prompt-prefix `TextBlock` (mono, `TextMuteBrush`) + a borderless mono `TextBox`:
|
||
- Bound `Text="{Binding ReviewFeedback, Mode=TwoWay}"`.
|
||
- `AcceptsReturn="True"`, `TextWrapping="Wrap"`, transparent background, no border.
|
||
- Starts ~1 line tall; grows with content up to `MaxHeight≈160`, then scrolls.
|
||
- `PlaceholderText` e.g. "Feedback for the next run…".
|
||
- Right-aligned button strip:
|
||
- `[Retry]` — `Classes="btn accent"` → `RejectReviewCommand`.
|
||
- `[Reset]` — `Classes="btn"` → `ParkReviewCommand`.
|
||
|
||
`[Accept]` is **not** in the footer; approval happens on the Git tab via
|
||
`ApproveReviewCommand`. The old `Cancel` review button is dropped from this UI; cancel
|
||
remains reachable through the task's existing cancel control (`CancelReviewCommand`
|
||
stays on the ViewModel, just not surfaced here).
|
||
|
||
### Enter handling (`WorkConsole.axaml.cs`)
|
||
|
||
- Handle `KeyDown` on the input `TextBox`:
|
||
- **Enter** without Shift → execute `RejectReviewCommand` (if it can execute) and set
|
||
`e.Handled = true`.
|
||
- **Shift+Enter** → fall through to default behavior (inserts newline).
|
||
- `RejectReviewAsync` already returns early on whitespace-only feedback
|
||
(`DetailsIslandViewModel.cs:1464`), so pressing Enter with an empty prompt is a no-op
|
||
with no extra guard needed.
|
||
|
||
## Command mapping
|
||
|
||
| Button | Location | Command | Effect |
|
||
| --- | --- | --- | --- |
|
||
| `[Retry]` | Output footer | `RejectReviewCommand` | Reject-to-queue with feedback; resumes the session (Queued). |
|
||
| `[Reset]` | Output footer | `ParkReviewCommand` | Park back to Idle. |
|
||
| `[Approve]` | Git tab | `ApproveReviewCommand` | Merge `SelectedMergeTarget` → Done (conflict keeps it in review). |
|
||
|
||
## Copy / empty state
|
||
|
||
- Update the Session empty-state text (`WorkConsole.axaml:270`) — it currently says
|
||
"review and merge controls appear here once the run finishes", which is no longer
|
||
accurate. Reword to reflect that only outcomes live on Session.
|
||
- Button labels remain literal strings (`Retry`, `Reset`, `Approve`), matching the
|
||
existing review buttons (no new localization keys).
|
||
|
||
## Out of scope
|
||
|
||
- No changes to worker-side review/merge logic or `IWorkerClient` signatures.
|
||
- No merge-target selector duplicated into the terminal footer (Approve uses the Git
|
||
tab dropdown / default target).
|
||
- No command renames on the ViewModel.
|
||
|
||
## Testing / verification
|
||
|
||
- Build `ClaudeDo.App` and `ClaudeDo.Worker` in `-c Release`.
|
||
- Manual visual verification (must be flagged — cannot be auto-verified):
|
||
- Footer appears only in `WaitingForReview`, on the Output tab.
|
||
- Enter sends Retry; Shift+Enter inserts a newline; empty Enter does nothing.
|
||
- Git tab shows Approve + merge/worktree controls; Session shows only outcomes.
|