Unify pane hold state and expiry handling

This commit is contained in:
Ian Gulliver
2026-10-22 08:49:34 -07:00
parent 22f73a3bad
commit 88c0199845
2 changed files with 28 additions and 45 deletions
+24 -37
View File
@@ -518,15 +518,18 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
}
m.mu.Lock()
working := m.paneFocus[user.Login].Focused || m.paneFocus[user.Login].Drafting
humanMoved := m.humanMoved[user.Login]
since := time.Since(humanMoved)
move := m.moveHolds[user.Login]
start := m.startHolds[user.Login]
since := time.Since(move.at)
moveHeld := since < moveHold
startHeld := !moveHeld && time.Since(m.startedTodo[user.Login]) < startHold
startHeld := !moveHeld && time.Since(start.at) < startHold
if moveHeld {
m.moveRefused[user.Login] = true
move.refused = true
m.moveHolds[user.Login] = move
}
if startHeld {
m.startRefused[user.Login] = true
start.refused = true
m.startHolds[user.Login] = start
}
m.mu.Unlock()
if moveHeld {
@@ -596,13 +599,12 @@ func (m *Manager) SetFocus(ctx context.Context, login string, f api.Focus, actor
m.mu.Lock()
m.paneMoved[login] = at
if actor == login {
m.humanMoved[login] = at
delete(m.moveRefused, login)
m.moveHolds[login] = showHold{at: at}
}
m.mu.Unlock()
if actor == login {
time.AfterFunc(moveHold, func() {
err := m.endMoveHold(context.Background(), login, at)
err := m.endShowHold(context.Background(), login, at, m.moveHolds, moveHoldEnded)
if err != nil {
slog.Error("end move hold", "login", login, "err", err)
}
@@ -702,21 +704,24 @@ const moveHold = 10 * time.Second
const moveHoldEnded = "The move hold is over: the human moved the right pane 10 seconds ago and hasn't moved it since, and a show of yours was refused in that time, so show works again under its other rules."
func (m *Manager) endMoveHold(ctx context.Context, login string, at time.Time) error {
type showHold struct {
at time.Time
refused bool
}
func (m *Manager) endShowHold(ctx context.Context, login string, at time.Time, holds map[string]showHold, text string) error {
m.mu.Lock()
current, ok := m.humanMoved[login]
if !ok || !current.Equal(at) {
hold := holds[login]
if !hold.at.Equal(at) {
m.mu.Unlock()
return nil
}
delete(m.humanMoved, login)
refused := m.moveRefused[login]
delete(m.moveRefused, login)
delete(holds, login)
m.mu.Unlock()
if !refused {
if !hold.refused {
return nil
}
return m.addLeadInput(ctx, store.LeadInput{Owner: login, Kind: store.LeadSignal, Actor: "byre", Text: moveHoldEnded})
return m.addLeadInput(ctx, store.LeadInput{Owner: login, Kind: store.LeadSignal, Actor: "byre", Text: text})
}
const startHold = 10 * time.Second
@@ -726,38 +731,20 @@ const startHoldEnded = "The start hold is over: the human started a TODO item 10
func (m *Manager) setStartedTodo(login string, started bool) {
m.mu.Lock()
defer m.mu.Unlock()
delete(m.startRefused, login)
if !started {
delete(m.startedTodo, login)
delete(m.startHolds, login)
return
}
at := time.Now()
m.startedTodo[login] = at
m.startHolds[login] = showHold{at: at}
time.AfterFunc(startHold, func() {
err := m.endStartHold(context.Background(), login, at)
err := m.endShowHold(context.Background(), login, at, m.startHolds, startHoldEnded)
if err != nil {
slog.Error("end start hold", "login", login, "err", err)
}
})
}
func (m *Manager) endStartHold(ctx context.Context, login string, at time.Time) error {
m.mu.Lock()
current, ok := m.startedTodo[login]
if !ok || !current.Equal(at) {
m.mu.Unlock()
return nil
}
delete(m.startedTodo, login)
refused := m.startRefused[login]
delete(m.startRefused, login)
m.mu.Unlock()
if !refused {
return nil
}
return m.addLeadInput(ctx, store.LeadInput{Owner: login, Kind: store.LeadSignal, Actor: "byre", Text: startHoldEnded})
}
func (m *Manager) modelOr(model string, l *live) string {
if model != "" {
return model
+4 -8
View File
@@ -58,10 +58,8 @@ type Manager struct {
paneFocus map[string]api.PaneFocus
paneReported map[string]time.Time
paneMoved map[string]time.Time
humanMoved map[string]time.Time
moveRefused map[string]bool
startedTodo map[string]time.Time
startRefused map[string]bool
moveHolds map[string]showHold
startHolds map[string]showHold
handoffModel map[string]string
mergeTurns map[string]mergeTurn
@@ -163,10 +161,8 @@ func New(st *store.Store, worktreeRoot, leadRoot, handsRoot, codexHome, antigrav
paneFocus: map[string]api.PaneFocus{},
paneReported: map[string]time.Time{},
paneMoved: map[string]time.Time{},
humanMoved: map[string]time.Time{},
moveRefused: map[string]bool{},
startedTodo: map[string]time.Time{},
startRefused: map[string]bool{},
moveHolds: map[string]showHold{},
startHolds: map[string]showHold{},
handoffModel: map[string]string{},
mergeTurns: map[string]mergeTurn{},
signals: make(chan []api.Event, 1024),