Lock the right pane while focused, add project focus, quiet lead

This commit is contained in:
Ian Gulliver
2026-10-15 09:59:13 -07:00
parent bdd1ae48f0
commit fdd005b591
32 changed files with 576 additions and 227 deletions
+26 -3
View File
@@ -292,10 +292,12 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
}),
tool("show",
"Point the human's right pane at a 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). Omit task_id to clear the pane.",
"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.",
`{"type": "object", "properties": {
"task_id": {"type": "string"},
"project_id": {"type": "string", "description": "Ignored when task_id is given."},
"tabs": {"type": "array", "items": {"type": "string", "enum": ["transcript", "changes", "files", "inbox", "todo"]}},
"tab": {"type": "string", "enum": ["transcript", "changes", "files", "inbox", "todo"]}
}, "required": ["tabs", "tab"]}`,
@@ -305,6 +307,12 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
if err != nil {
return "", err
}
m.mu.Lock()
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)
}
err = m.SetFocus(ctx, user.Login, f, leadActor(user.Login))
if err != nil {
return "", err
@@ -333,15 +341,30 @@ func (m *Manager) SetFocus(ctx context.Context, login string, f api.Focus, actor
if f.TaskId != nil && *f.TaskId == "" {
f.TaskId = nil
}
if f.ProjectId != nil && *f.ProjectId == "" {
f.ProjectId = nil
}
if f.TaskId != nil {
_, _, err := m.activeTask(ctx, *f.TaskId)
task, _, err := m.activeTask(ctx, *f.TaskId)
if err != nil {
return err
}
f.ProjectId = &task.ProjectId
} else if f.ProjectId != nil {
_, err := m.store.GetProject(ctx, *f.ProjectId)
if err != nil {
return fmt.Errorf("project %s: %w", *f.ProjectId, err)
}
}
return m.store.SetFocus(ctx, login, f, actor)
}
func (m *Manager) SetPaneFocus(login string, focused bool) {
m.mu.Lock()
defer m.mu.Unlock()
m.paneFocused[login] = focused
}
func (m *Manager) modelOr(model string, l *live) string {
if model != "" {
return model