feat(tui-go): approval ergonomics — queue + tier-gated confirm (E §3)
- pending approvals are a navigable queue (PendingQueue/PendingIdx; ↑↓/jk, count
shown), no modal stacking; resolve removes the specific gate by request id
- y/n/e keys (approve/reject/steer); T0–T2 act on one key, T3+ requires arm+confirm
("press y again"), any other key disarms; reject/steer/auto never gated
- snapshot restore now rehydrates the full pending list, not just the first
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -132,6 +132,13 @@ func (m Model) renderApprovalBand(h int) string {
|
||||
rightHdr := t.span("tier ", t.P.Faint) + t.span(a.Tier, t.P.Accent2) +
|
||||
t.span(" · risk ", t.P.Faint) +
|
||||
lipgloss.NewStyle().Foreground(riskColor).Background(t.P.Bg).Bold(true).Render(strings.ToUpper(a.Risk))
|
||||
// When more than one gate is queued, show "approval i/n" so the operator knows
|
||||
// there are others behind this one (↑/↓ to walk them) — never stack modals.
|
||||
if n := len(s.PendingQueue); n > 1 {
|
||||
rightHdr = t.span("approval ", t.P.Faint) +
|
||||
t.span(itoa(s.PendingIdx+1)+"/"+itoa(n), t.P.Accent) +
|
||||
t.span(" · ", t.P.Faint) + rightHdr
|
||||
}
|
||||
|
||||
innerH := h - 2
|
||||
ratBlock := 0
|
||||
@@ -218,8 +225,19 @@ func (m Model) approvalActions() string {
|
||||
hint("enter", "approve + send note"), hint("esc", "keep note, decide below"),
|
||||
}, gap)
|
||||
}
|
||||
parts := []string{hint("a", "approve"), hint("A", "auto"), hint("s", "steer"), hint("r", "reject")}
|
||||
if s := m.session(m.selectedID); s != nil && s.Pending != nil &&
|
||||
s := m.session(m.selectedID)
|
||||
// Armed T3+ approve: a single decisive line so an accidental keystroke can't slip
|
||||
// a destructive action through — the confirm key must be pressed again.
|
||||
if m.approvalArmed && s != nil && s.Pending != nil {
|
||||
warn := lipgloss.NewStyle().Foreground(t.P.Bad).Background(t.P.Bg).Bold(true).
|
||||
Render("press y again to confirm " + s.Pending.Tier + " approval")
|
||||
return warn + gap + hint("any other key", "cancel")
|
||||
}
|
||||
parts := []string{hint("y", "approve"), hint("n", "reject"), hint("e", "steer"), hint("A", "auto")}
|
||||
if s != nil && len(s.PendingQueue) > 1 {
|
||||
parts = append(parts, hint("↑↓", "queue"))
|
||||
}
|
||||
if s != nil && s.Pending != nil &&
|
||||
(isUnifiedDiff(s.Pending.Preview) || isCommandApproval(s.Pending)) {
|
||||
parts = append(parts, hint("^x", "fullscreen"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user