Free the right pane for the lead once its inbox empties or task merges

This commit is contained in:
Ian Gulliver
2026-10-15 10:26:26 -07:00
parent 40595d4c5a
commit a569cf94c7
5 changed files with 149 additions and 36 deletions
+39 -2
View File
@@ -294,7 +294,8 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
tool("show",
"Point the human's right pane at a task, or at a project with no task: tabs are the tabs to put first, in order (the rest follow), and tab is the one to select. "+
"Tabs: transcript, changes, files, inbox (the task's open items), todo (the project's TODO.md); with only project_id, only todo shows anything. "+
"Omit both task_id and project_id to clear the pane. Refused while the human is working in the right pane.",
"Omit both task_id and project_id to clear the pane. "+
"Refused while the human is working in the right pane, unless what it shows is finished (a merged or discarded task, or an inbox tab with nothing left).",
`{"type": "object", "properties": {
"task_id": {"type": "string"},
"project_id": {"type": "string", "description": "Ignored when task_id is given."},
@@ -311,7 +312,17 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
focused := m.paneFocused[user.Login]
m.mu.Unlock()
if focused {
return "", fmt.Errorf("%w: the human is working in the right pane, so it was left as it is; tell them in chat instead", ErrConflict)
current, err := m.store.GetFocus(ctx, user.Login)
if err != nil {
return "", err
}
finished, err := m.paneFinished(ctx, current)
if err != nil {
return "", err
}
if finished == "" {
return "", fmt.Errorf("%w: the human is working in the right pane, so it was left as it is; tell them in chat instead", ErrConflict)
}
}
err = m.SetFocus(ctx, user.Login, f, leadActor(user.Login))
if err != nil {
@@ -359,6 +370,32 @@ func (m *Manager) SetFocus(ctx context.Context, login string, f api.Focus, actor
return m.store.SetFocus(ctx, login, f, actor)
}
const inboxEmptied = "has nothing left in its inbox"
func (m *Manager) paneFinished(ctx context.Context, f api.Focus) (string, error) {
if f.TaskId == nil {
return "", nil
}
task, err := m.store.GetTask(ctx, *f.TaskId)
if err != nil {
return "", err
}
if task.Status != api.TaskStatusActive {
return "is " + string(task.Status), nil
}
if f.Tab != api.TabInbox {
return "", nil
}
items, err := m.store.ListInbox(ctx, store.InboxFilter{State: api.Open, TaskID: task.Id})
if err != nil {
return "", err
}
if len(items) > 0 {
return "", nil
}
return inboxEmptied, nil
}
func (m *Manager) SetPaneFocus(login string, focused bool) {
m.mu.Lock()
defer m.mu.Unlock()