feat(tui): full event history, approval-decision events, status bar

- Events were hard-capped to the last 7 per session in addEvent, so the
  e-inspector and EVENTS panel could never show more. Raise to 1000
  (effectively all, bounded); the EVENTS panel now shows the latest that
  fit (tail), and the inspector scrolls a window around the selection
  with a position indicator.
- The TUI had no approval.resolved handling at all — the decision frame
  was ignored and pending only cleared on session.resumed. Add the
  constant + case: clear the gate and record an ApprovalResolved event
  (APPROVED/REJECTED/AUTO_APPROVED + reason) into the stream.
- Status bar now shows the current stage and session status alongside the
  name. Relabel the cryptic "N bg" badge to "N elsewhere".
This commit is contained in:
2026-06-03 01:24:52 +04:00
parent b56f0e88ca
commit f7fc10ddf5
4 changed files with 63 additions and 14 deletions
+17 -2
View File
@@ -177,6 +177,16 @@ func (m *Model) applyServer(msg protocol.ServerMessage) {
}
case protocol.TypeApprovalRequired:
m.onApprovalRequired(msg)
case protocol.TypeApprovalResolved:
if s := m.session(msg.SessionID); s != nil {
s.Pending = nil
detail := msg.Outcome
if msg.Reason != "" {
detail += " — " + msg.Reason
}
s.addEvent(msg.OccurredAt, "ApprovalResolved", detail)
s.LastEventAt = nowMillis()
}
case protocol.TypeSessionSnapshot:
m.onSnapshot(msg)
case protocol.TypeStageManifest:
@@ -335,10 +345,15 @@ func (m *Model) touch(id, status string) {
// --- Session helpers ---
// maxSessionEvents bounds retained per-session history (effectively "all" for a
// session, while keeping memory bounded on very long runs). The EVENTS panel
// shows the tail that fits; the `e` inspector scrolls the full retained list.
const maxSessionEvents = 1000
func (s *Session) addEvent(epochMillis int64, typ, detail string) {
s.Events = append(s.Events, EventEntry{formatTime(epochMillis), typ, detail})
if len(s.Events) > 7 {
s.Events = s.Events[len(s.Events)-7:]
if len(s.Events) > maxSessionEvents {
s.Events = s.Events[len(s.Events)-maxSessionEvents:]
}
s.LastEventAt = epochMillis
}