re-switch

This commit is contained in:
Ian Gulliver
2026-10-16 13:10:44 -07:00
parent 1296abcf4b
commit 7951b73030
4 changed files with 39 additions and 1 deletions
+35
View File
@@ -362,6 +362,7 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
"Tabs: transcript, changes, files, terminal (a shell in the task's worktree), inbox (the task's open items), reviews (the task's reviews by reviewer agents), workflow (a workflow stage task's run: its graph and each stage's state, attempts and outputs), project (the project's dashboard: its active tasks and its TODO.md items); with only project_id, only project shows anything. "+
"Omit both task_id and project_id to clear the pane. "+
"If the pane already shows that task (or project) on that tab, only the tab order changes and you are told so, even while the human is working in the pane. "+
"Otherwise refused for 10 seconds after the human last moved the pane themselves (switching task or tab), whatever else holds; byre signals you \"The move hold is over\" when those 10 seconds pass without another move. "+
"Otherwise refused while the human is working in the right pane, unless it is on the project tab, or what it shows is finished (a merged or discarded task, or an inbox tab with nothing left), "+
"or it is on the transcript tab of a task whose agent is mid-turn, the human has no unsent text there, and either the human sent the message that started that turn since the pane last moved or the pane moved there 10 seconds ago or more; byre signals you \"Your right pane is free\" when either happens. "+
"Also refused while the pane is on the project tab and the human started a TODO item there in the last 10 seconds, unless they switched task or tab or messaged you since; byre signals you \"The start hold is over\" when those 10 seconds pass with the pane still on the project tab.",
@@ -393,8 +394,12 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
}
m.mu.Lock()
focused := m.paneFocus[user.Login].Focused
humanMoved := m.humanMoved[user.Login]
startedTodo := m.startedTodo[user.Login]
m.mu.Unlock()
if since := time.Since(humanMoved); since < moveHold {
return "", fmt.Errorf("%w: the human moved the right pane %s ago, so it was left as it is; tell them in chat instead. The hold ends %s after their last move; byre signals you \"The move hold is over\" when it ends", ErrConflict, since.Round(time.Second), moveHold)
}
if time.Since(startedTodo) < startHold && current.Tab == api.TabProject {
return "", fmt.Errorf("%w: the human just started a TODO item from the project tab and is likely to start more; tell them in chat instead. The hold ends %s after that start, unless they move the pane or message you first; byre signals you \"The start hold is over\" when it ends", ErrConflict, startHold)
}
@@ -463,8 +468,17 @@ func (m *Manager) SetFocus(ctx context.Context, login string, f api.Focus, actor
at := time.Now()
m.mu.Lock()
m.paneMoved[login] = at
if actor == login {
m.humanMoved[login] = at
}
m.mu.Unlock()
if actor == login {
time.AfterFunc(moveHold, func() {
err := m.endMoveHold(context.Background(), login, at)
if err != nil {
slog.Error("end move hold", "login", login, "err", err)
}
})
time.AfterFunc(watchHold, func() {
err := m.endWatchHold(context.Background(), login, at)
if err != nil {
@@ -576,6 +590,27 @@ func (m *Manager) SetPaneFocus(login string, p api.PaneFocus) {
m.paneReported[login] = time.Now()
}
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, so show works again under its other rules."
func (m *Manager) endMoveHold(ctx context.Context, login string, at time.Time) error {
m.mu.Lock()
current, ok := m.humanMoved[login]
if !ok || !current.Equal(at) {
m.mu.Unlock()
return nil
}
delete(m.humanMoved, login)
m.mu.Unlock()
err := m.store.AddLeadInput(ctx, store.LeadInput{Owner: login, Kind: store.LeadSignal, Actor: "byre", Text: moveHoldEnded})
if err != nil {
return err
}
m.deliverLead(login)
return nil
}
const startHold = 10 * time.Second
const startHoldEnded = "The start hold is over: the human started a TODO item from the project tab 10 seconds ago and the pane is still there, so show works again."