TUI: Closed column, legacy 30m stale window, filtered-view fix, header shown-count, toggle tests
This commit is contained in:
66
main.go
66
main.go
@@ -67,7 +67,8 @@ var sortNames = map[int]string{
|
||||
type model struct {
|
||||
table table.Model
|
||||
help help.Model
|
||||
agents []AgentState // filtered + sorted view
|
||||
agents []AgentState // all agents from the last poll (unfiltered)
|
||||
view []AgentState // filtered + sorted view backing the table
|
||||
config Config
|
||||
hideClosed bool
|
||||
hideSubagents bool
|
||||
@@ -86,10 +87,10 @@ func initialModel(cfg Config) model {
|
||||
{Title: "Session", Width: 16},
|
||||
{Title: "Folder", Width: 16},
|
||||
{Title: "Status", Width: 10},
|
||||
{Title: "Model", Width: 14},
|
||||
{Title: "Started", Width: 10},
|
||||
{Title: "Closed", Width: 10},
|
||||
{Title: "Tools", Width: 5},
|
||||
{Title: "Task", Width: 24},
|
||||
{Title: "Task", Width: 20},
|
||||
}
|
||||
|
||||
t := table.New(
|
||||
@@ -229,7 +230,7 @@ func (m model) View() string {
|
||||
live++
|
||||
}
|
||||
}
|
||||
summary := fmt.Sprintf("%d agent(s) · %d live · %d closed", len(m.agents), live, closed)
|
||||
summary := fmt.Sprintf("%d shown of %d agents · %d live · %d closed", len(m.view), len(m.agents), live, closed)
|
||||
if m.hideClosed {
|
||||
summary += " │ closed hidden"
|
||||
}
|
||||
@@ -273,14 +274,14 @@ func (m model) View() string {
|
||||
}
|
||||
|
||||
func (m model) detailView() string {
|
||||
if len(m.agents) == 0 {
|
||||
if len(m.view) == 0 {
|
||||
return ""
|
||||
}
|
||||
row := m.table.Cursor()
|
||||
if row < 0 || row >= len(m.agents) {
|
||||
if row < 0 || row >= len(m.view) {
|
||||
return ""
|
||||
}
|
||||
a := m.agents[row]
|
||||
a := m.view[row]
|
||||
|
||||
stale := m.staleAfter()
|
||||
term := a.TerminalType
|
||||
@@ -373,6 +374,7 @@ func (m *model) updateTable() {
|
||||
}
|
||||
view = append(view, a)
|
||||
}
|
||||
m.view = view
|
||||
|
||||
// Sort
|
||||
sortAgents(view, m.sortMode, m.staleAfter())
|
||||
@@ -385,16 +387,24 @@ func (m *model) updateTable() {
|
||||
session = "◇ " + session
|
||||
}
|
||||
task := strings.ReplaceAll(a.CurrentTask, "\n", " ")
|
||||
if len(task) > 24 {
|
||||
task = task[:22] + ".."
|
||||
if len(task) > 20 {
|
||||
task = task[:18] + ".."
|
||||
}
|
||||
var closedTime string
|
||||
if a.IsClosed(m.staleAfter()) {
|
||||
if a.ClosedAt != nil && *a.ClosedAt != "" {
|
||||
closedTime = fmtTime(a.ClosedAt)
|
||||
} else {
|
||||
closedTime = fmtTime(a.LastSeenAt) // approx: last seen
|
||||
}
|
||||
}
|
||||
rows = append(rows, table.Row{
|
||||
termSymbol(a.TerminalType, a.ConnectionType),
|
||||
trunc(session, 16),
|
||||
trunc(a.Folder(), 16),
|
||||
a.StatusStr(m.staleAfter()),
|
||||
a.ShortModel(),
|
||||
fmtTime(a.SessionStartedAt),
|
||||
closedTime,
|
||||
fmt.Sprintf("%d", a.ToolCalls),
|
||||
task,
|
||||
})
|
||||
@@ -507,14 +517,14 @@ type errMsg struct{ err error }
|
||||
// `zellij action switch-session` when the dashboard itself runs inside zellij
|
||||
// - direct → no attach target; show an error
|
||||
func attachToAgent(m model) tea.Cmd {
|
||||
if len(m.agents) == 0 {
|
||||
if len(m.view) == 0 {
|
||||
return nil
|
||||
}
|
||||
row := m.table.Cursor()
|
||||
if row < 0 || row >= len(m.agents) {
|
||||
if row < 0 || row >= len(m.view) {
|
||||
return nil
|
||||
}
|
||||
a := m.agents[row]
|
||||
a := m.view[row]
|
||||
|
||||
term := a.TerminalType
|
||||
if term == "" {
|
||||
@@ -573,14 +583,14 @@ func attachToAgent(m model) tea.Cmd {
|
||||
// openHunk reviews the selected agent's changes with Hunk, in the folder
|
||||
// the agent was actually running in.
|
||||
func openHunk(m model) tea.Cmd {
|
||||
if len(m.agents) == 0 {
|
||||
if len(m.view) == 0 {
|
||||
return nil
|
||||
}
|
||||
row := m.table.Cursor()
|
||||
if row < 0 || row >= len(m.agents) {
|
||||
if row < 0 || row >= len(m.view) {
|
||||
return nil
|
||||
}
|
||||
a := m.agents[row]
|
||||
a := m.view[row]
|
||||
|
||||
if a.Cwd == "" {
|
||||
m.err = fmt.Errorf("no folder recorded for %s", a.Session)
|
||||
@@ -628,10 +638,10 @@ func openTuxedo(m model) tea.Cmd {
|
||||
var todoPath string
|
||||
var agent AgentState
|
||||
haveAgent := false
|
||||
if len(m.agents) > 0 {
|
||||
if len(m.view) > 0 {
|
||||
row := m.table.Cursor()
|
||||
if row >= 0 && row < len(m.agents) {
|
||||
agent = m.agents[row]
|
||||
if row >= 0 && row < len(m.view) {
|
||||
agent = m.view[row]
|
||||
haveAgent = true
|
||||
if agent.Cwd != "" {
|
||||
todoPath = agent.Cwd + "/.pi/dashboard/tasks/todo.txt"
|
||||
@@ -732,22 +742,32 @@ func printAgentList(agents []AgentState) {
|
||||
fmt.Println("No agents found in ~/.pi/agent/dashboard/")
|
||||
return
|
||||
}
|
||||
fmt.Printf("%-6s %-18s %-16s %-10s %-10s %s\n", "Type", "Session", "Folder", "Status", "Started", "Task")
|
||||
fmt.Println(strings.Repeat("-", 100))
|
||||
stale := 45 * time.Second
|
||||
fmt.Printf("%-6s %-18s %-16s %-10s %-10s %-10s %s\n", "Type", "Session", "Folder", "Status", "Started", "Closed", "Task")
|
||||
fmt.Println(strings.Repeat("-", 110))
|
||||
for _, a := range agents {
|
||||
task := strings.ReplaceAll(a.CurrentTask, "\n", " ")
|
||||
if len(task) > 35 {
|
||||
task = task[:33] + ".."
|
||||
}
|
||||
fmt.Printf("%-6s %-18s %-16s %-10s %-10s %s\n",
|
||||
var closedTime string
|
||||
if a.IsClosed(stale) {
|
||||
if a.ClosedAt != nil && *a.ClosedAt != "" {
|
||||
closedTime = fmtTime(a.ClosedAt)
|
||||
} else {
|
||||
closedTime = fmtTime(a.LastSeenAt)
|
||||
}
|
||||
}
|
||||
fmt.Printf("%-6s %-18s %-16s %-10s %-10s %-10s %s\n",
|
||||
termSymbol(a.TerminalType, a.ConnectionType),
|
||||
trunc(a.Session, 18),
|
||||
trunc(a.Folder(), 16),
|
||||
statusStr(a),
|
||||
fmtTime(a.SessionStartedAt),
|
||||
closedTime,
|
||||
task)
|
||||
}
|
||||
fmt.Println(strings.Repeat("-", 100))
|
||||
fmt.Println(strings.Repeat("-", 110))
|
||||
fmt.Println("Type: Ⓣ tmux · Ⓩ zellij · ⓉⓏ both · · direct")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user