tab order

This commit is contained in:
Ian Gulliver
2026-10-19 08:56:37 -07:00
parent 32ea6da327
commit dec87b3dc3
10 changed files with 292 additions and 298 deletions
+6 -17
View File
@@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"log/slog"
"slices"
"strings"
"time"
@@ -456,11 +455,11 @@ 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. "+
"Point the human's right pane at a task, or at a project with no task, and select one of its tabs. The tabs' order is fixed. "+
"Whenever the human asks you to show something (\"show me that when you can\") or you want to show something, call show right away; never hold back because you expect a refusal, since only a refused show arranges byre's signal to try again. "+
"Tabs: transcript, board (a team task's board: its agents' posts, the human's and yours), changes, files, terminal (a shell in the task's worktree), questions (the task's oldest open question), 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. "+
"If the pane already shows that task (or project) on that tab, nothing changes and you are told so. "+
"Otherwise refused for 10 seconds after the human last moved the pane themselves (switching task or tab), whatever else holds; if a show was refused for it, byre signals you \"The move hold is over\" when those 10 seconds pass without another move, and sends no signal otherwise. "+
"Otherwise refused while the human is working in the right pane (focused in it, or with unsent text in it), unless it is on the project tab, or what it shows is finished (a merged or discarded task, or a questions tab with nothing left open),"+
"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. "+
@@ -468,9 +467,8 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
`{"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", "board", "changes", "files", "terminal", "questions", "reviews", "workflow", "project"]}},
"tab": {"type": "string", "enum": ["transcript", "board", "changes", "files", "terminal", "questions", "reviews", "workflow", "project"]}
}, "required": ["tabs", "tab"]}`,
}, "required": ["tab"]}`,
func(ctx context.Context, user api.User, raw json.RawMessage) (string, error) {
f := api.Focus{}
err := json.Unmarshal(raw, &f)
@@ -482,14 +480,7 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
return "", err
}
if sameView(current, f) {
if slices.Equal(current.Tabs, f.Tabs) {
return "Already shown: the right pane shows that now, so nothing changed.", nil
}
err = m.SetFocus(ctx, user.Login, f, leadActor(user.Login))
if err != nil {
return "", err
}
return "Already shown on that tab; the tab order was updated.", nil
return "Already shown: the right pane shows that now, so nothing changed.", nil
}
m.mu.Lock()
working := m.paneFocus[user.Login].Focused || m.paneFocus[user.Login].Drafting
@@ -546,10 +537,8 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
}
func (m *Manager) SetFocus(ctx context.Context, login string, f api.Focus, actor string) error {
for _, t := range append(slices.Clone(f.Tabs), f.Tab) {
if !t.Valid() {
return fmt.Errorf("%w: unknown tab %q", ErrInvalid, t)
}
if !f.Tab.Valid() {
return fmt.Errorf("%w: unknown tab %q", ErrInvalid, f.Tab)
}
if f.TaskId != nil && *f.TaskId == "" {
f.TaskId = nil