agent tracker update

This commit is contained in:
David Chen 2026-04-02 13:45:55 -07:00
parent 5064629d61
commit 0bfcb8d7c3
31 changed files with 1741 additions and 3320 deletions

View file

@ -55,6 +55,7 @@ type paletteModel struct {
todo *todoPanelModel
activity *activityMonitorBT
devices *devicePanelModel
status *statusRightPanelModel
tracker *trackerPanelModel
}
@ -329,15 +330,6 @@ func (r *paletteRuntime) persistRecord(update func(*agentRecord) error) error {
}
func (r *paletteRuntime) buildActions() []paletteAction {
memoryDisplayEnabled := paletteMemoryDisplayEnabled()
memoryTitle := "Hide memory display"
memorySubtitle := "Hide bottom-right tmux memory stats"
memoryKeywords := []string{"tmux", "memory", "status", "status-right", "hide", "bottom-right"}
if !memoryDisplayEnabled {
memoryTitle = "Show memory display"
memorySubtitle = "Show bottom-right tmux memory stats"
memoryKeywords = []string{"tmux", "memory", "status", "status-right", "show", "bottom-right"}
}
actions := []paletteAction{
{
Section: "Agent",
@ -402,10 +394,10 @@ func (r *paletteRuntime) buildActions() []paletteAction {
},
paletteAction{
Section: "System",
Title: memoryTitle,
Subtitle: memorySubtitle,
Keywords: memoryKeywords,
Kind: paletteActionToggleMemoryDisplay,
Title: "Bottom-right status",
Subtitle: "Open control center for tmux right-side status modules",
Keywords: []string{"tmux", "status", "status-right", "bottom-right", "control", "center", "istat", "cpu", "network", "memory", "notes", "host", "flash"},
Kind: paletteActionOpenStatusRight,
},
)
if strings.TrimSpace(r.agentID) == "" {
@ -414,20 +406,6 @@ func (r *paletteRuntime) buildActions() []paletteAction {
if r.record == nil {
return actions
}
for idx, todo := range r.record.Dashboard.Todos {
status := "open"
if todo.Done {
status = "done"
}
actions = append(actions, paletteAction{
Section: "Agent",
Title: fmt.Sprintf("Toggle todo: %s", todo.Title),
Subtitle: fmt.Sprintf("Mark todo %s", status),
Keywords: []string{"agent", "todo", "toggle", status, todo.Title},
Kind: paletteActionToggleTodo,
TodoIndex: idx,
})
}
return actions
}
@ -568,15 +546,6 @@ func (r *paletteRuntime) execute(result paletteResult) (bool, string, error) {
action := result.Action
text := strings.TrimSpace(result.Input)
switch action.Kind {
case paletteActionToggleTodo:
err := r.persistRecord(func(record *agentRecord) error {
if action.TodoIndex < 0 || action.TodoIndex >= len(record.Dashboard.Todos) {
return fmt.Errorf("todo no longer exists")
}
record.Dashboard.Todos[action.TodoIndex].Done = !record.Dashboard.Todos[action.TodoIndex].Done
return nil
})
return false, "", err
case paletteActionPromptStartAgent:
if err := r.runAgentStart(action.RepoRoot, text, result.Device, result.KeepWorktree); err != nil {
return true, "", err
@ -598,35 +567,59 @@ func (r *paletteRuntime) execute(result paletteResult) (bool, string, error) {
return false, "", nil
case paletteActionReloadTmuxConfig:
return false, "", paletteTmuxRunner("source-file", os.Getenv("HOME")+"/.config/.tmux.conf")
case paletteActionToggleMemoryDisplay:
return false, "", togglePaletteMemoryDisplay()
default:
return false, "", nil
}
}
func paletteMemoryDisplayEnabled() bool {
out, err := paletteTmuxOutput("show-environment", "-g", "TMUX_STATUS_MEMORY")
if err != nil {
return true
func statusRightModuleLabel(module string) string {
switch module {
case statusRightModuleCPU:
return "CPU"
case statusRightModuleNetwork:
return "Network"
case statusRightModuleMemory:
return "Memory"
case statusRightModuleMemoryTotals:
return "Tmux Memory"
case statusRightModuleAgent:
return "Agent"
case statusRightModuleNotes:
return "Notes"
case statusRightModuleFlashMoe:
return "Flash-MoE"
case statusRightModuleHost:
return "Host"
default:
return module
}
line := strings.TrimSpace(out)
if strings.HasPrefix(line, "TMUX_STATUS_MEMORY=") {
value := strings.TrimSpace(strings.TrimPrefix(line, "TMUX_STATUS_MEMORY="))
switch strings.ToLower(value) {
case "0", "false", "off", "no":
return false
}
}
return true
}
func togglePaletteMemoryDisplay() error {
value := "0"
if !paletteMemoryDisplayEnabled() {
value = "1"
func statusRightModuleDescription(module string) string {
switch module {
case statusRightModuleCPU:
return "CPU usage"
case statusRightModuleNetwork:
return "network throughput"
case statusRightModuleMemory:
return "pane memory stats"
case statusRightModuleMemoryTotals:
return "window, session, and total tmux memory"
case statusRightModuleAgent:
return "active agent device"
case statusRightModuleNotes:
return "todo count"
case statusRightModuleFlashMoe:
return "Flash-MoE status"
case statusRightModuleHost:
return "hostname"
default:
return module
}
if err := paletteTmuxRunner("set-environment", "-g", "TMUX_STATUS_MEMORY", value); err != nil {
}
func togglePaletteStatusRightModule(module string) error {
if err := toggleStatusRightModule(module); err != nil {
return err
}
return paletteTmuxRunner("refresh-client", "-S")
@ -651,6 +644,9 @@ func newPaletteModel(runtime *paletteRuntime, state paletteUIState) *paletteMode
if state.Mode == paletteModeDevices {
model.openDevicesPanel()
}
if state.Mode == paletteModeStatusRight {
model.openStatusRightPanel()
}
if state.Mode == paletteModeTracker {
_, _ = model.openTrackerPanel()
}
@ -731,6 +727,19 @@ func (m *paletteModel) openDevicesPanel() {
m.state.ShowAltHints = false
}
func (m *paletteModel) openStatusRightPanel() {
if m.status == nil {
m.status = newStatusRightPanelModel()
} else {
m.status.reload()
m.status.requestBack = false
}
m.status.showAltHints = false
m.state.Mode = paletteModeStatusRight
m.state.Message = ""
m.state.ShowAltHints = false
}
func (m *paletteModel) openTrackerPanel() (tea.Cmd, error) {
if m.tracker == nil {
m.tracker = newTrackerPanelModel(m.runtime)
@ -765,8 +774,12 @@ func (m *paletteModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.tracker.width = msg.Width
m.tracker.height = msg.Height
}
if m.status != nil {
m.status.width = msg.Width
m.status.height = msg.Height
}
case tea.KeyMsg:
if m.state.Mode != paletteModeActivity && m.state.Mode != paletteModeTodos && m.state.Mode != paletteModeDevices && m.state.Mode != paletteModeTracker {
if m.state.Mode != paletteModeActivity && m.state.Mode != paletteModeTodos && m.state.Mode != paletteModeDevices && m.state.Mode != paletteModeStatusRight && m.state.Mode != paletteModeTracker {
if isAltFooterToggleKey(msg) {
m.state.ShowAltHints = !m.state.ShowAltHints
return m, nil
@ -842,6 +855,22 @@ func (m *paletteModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
return m, cmd
}
if m.state.Mode == paletteModeStatusRight {
if m.status == nil {
m.openStatusRightPanel()
}
model, cmd := m.status.Update(msg)
if updated, ok := model.(*statusRightPanelModel); ok {
m.status = updated
}
if m.status.requestBack {
m.status.requestBack = false
m.state.Mode = paletteModeList
m.state.Message = m.status.currentStatus()
return m, nil
}
return m, cmd
}
if m.state.Mode == paletteModeTracker {
if m.tracker == nil {
cmd, err := m.openTrackerPanel()
@ -918,6 +947,19 @@ func (m *paletteModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
return m, cmd
}
if m.state.Mode == paletteModeStatusRight && m.status != nil {
model, cmd := m.status.Update(msg)
if updated, ok := model.(*statusRightPanelModel); ok {
m.status = updated
}
if m.status.requestBack {
m.status.requestBack = false
m.state.Mode = paletteModeList
m.state.Message = m.status.currentStatus()
return m, nil
}
return m, cmd
}
if m.state.Mode == paletteModeTracker && m.tracker != nil {
model, cmd := m.tracker.Update(msg)
if updated, ok := model.(*trackerPanelModel); ok {
@ -1052,6 +1094,9 @@ func (m *paletteModel) selectAction(action paletteAction) (tea.Model, tea.Cmd) {
case paletteActionOpenDevices:
m.openDevicesPanel()
return m, nil
case paletteActionOpenStatusRight:
m.openStatusRightPanel()
return m, nil
default:
m.state.Mode = paletteModeList
m.result = paletteResult{Kind: paletteResultRunAction, Action: action, State: m.state}
@ -1376,6 +1421,14 @@ func (m *paletteModel) View() string {
}
return styles.muted.Render("Device panel unavailable")
}
if m.state.Mode == paletteModeStatusRight {
if m.status != nil {
m.status.width = width
m.status.height = height
return m.status.render(styles, width, height)
}
return styles.muted.Render("Status panel unavailable")
}
if m.state.Mode == paletteModeTracker {
if m.tracker != nil {
m.tracker.width = width
@ -1421,10 +1474,10 @@ func (m *paletteModel) renderListView(styles paletteStyles, width, height int) s
)
contentHeight := maxInt(8, height-7)
listWidth := maxInt(34, width*48/100)
dashboardWidth := maxInt(28, width-listWidth-3)
sidebarWidth := maxInt(28, width-listWidth-3)
list := m.renderActions(styles, actions, listWidth, contentHeight)
dashboard := m.renderDashboard(styles, dashboardWidth, contentHeight)
body := lipgloss.JoinHorizontal(lipgloss.Top, list, strings.Repeat(" ", 3), dashboard)
sidebar := m.renderSidebar(styles, sidebarWidth, contentHeight)
body := lipgloss.JoinHorizontal(lipgloss.Top, list, strings.Repeat(" ", 3), sidebar)
footer := renderPaletteFooter(styles, width, m.state.Message, m.state.ShowAltHints)
view := lipgloss.JoinVertical(lipgloss.Left, header, "", filterLine, "", body, "", footer)
return lipgloss.NewStyle().Width(width).Height(height).Padding(0, 1).Render(view)
@ -1486,9 +1539,9 @@ func (m *paletteModel) renderActions(styles paletteStyles, actions []paletteActi
return lipgloss.NewStyle().Width(width).Height(height).Render(content)
}
func (m *paletteModel) renderDashboard(styles paletteStyles, width, height int) string {
func (m *paletteModel) renderSidebar(styles paletteStyles, width, height int) string {
lines := []string{}
trackerContext, trackerAgent, trackerBootstrap := m.runtime.dashboardTrackerStatus()
trackerContext, trackerAgent, trackerBootstrap := m.runtime.sidebarTrackerStatus()
lines = append(lines, styles.panelTitle.Render("Tracker Status"))
lines = append(lines, renderPaletteStat(styles, "Context", trackerContext, width, 9))
lines = append(lines, renderPaletteStat(styles, "Agent", trackerAgent, width, 9))
@ -1496,7 +1549,7 @@ func (m *paletteModel) renderDashboard(styles paletteStyles, width, height int)
lines = append(lines, "")
lines = append(lines, styles.panelTitle.Render("Todo Preview"))
previewLimit := clampInt((height-6)/4, 1, 3)
sections := m.runtime.dashboardTodoPreviewSections()
sections := m.runtime.sidebarTodoPreviewSections()
for idx, section := range sections {
if idx > 0 {
lines = append(lines, "")
@ -1507,7 +1560,7 @@ func (m *paletteModel) renderDashboard(styles paletteStyles, width, height int)
return lipgloss.NewStyle().Width(width).Height(height).Render(content)
}
func (r *paletteRuntime) dashboardTrackerStatus() (contextSummary, agentSummary, bootstrapSummary string) {
func (r *paletteRuntime) sidebarTrackerStatus() (contextSummary, agentSummary, bootstrapSummary string) {
contextParts := []string{}
if r.currentSessionName != "" {
contextParts = append(contextParts, r.currentSessionName)
@ -1540,7 +1593,7 @@ func (r *paletteRuntime) dashboardTrackerStatus() (contextSummary, agentSummary,
return contextSummary, agentSummary, bootstrapSummary
}
func (r *paletteRuntime) dashboardTodoPreviewSections() []paletteTodoPreviewSection {
func (r *paletteRuntime) sidebarTodoPreviewSections() []paletteTodoPreviewSection {
sections := []paletteTodoPreviewSection{}
store, err := loadTmuxTodoStore()
windowID := strings.TrimSpace(r.windowID)
@ -1561,17 +1614,6 @@ func (r *paletteRuntime) dashboardTodoPreviewSections() []paletteTodoPreviewSect
Empty: "No global todos",
})
}
if r.record != nil {
section := paletteTodoPreviewSection{
Title: "Dashboard",
Items: paletteAgentTodoPreviewItems(r.record.Dashboard.Todos),
Empty: "No dashboard todos",
}
if currentTask := firstPaletteLine(r.record.Dashboard.CurrentTask); currentTask != "" {
section.Lead = "Task: " + currentTask
}
sections = append(sections, section)
}
return sections
}
@ -2128,18 +2170,6 @@ func paletteTmuxTodoPreviewItems(items []tmuxTodoItem) []paletteTodoPreviewItem
return rows
}
func paletteAgentTodoPreviewItems(todos []todoItem) []paletteTodoPreviewItem {
rows := make([]paletteTodoPreviewItem, 0, len(todos))
for _, todo := range todos {
title := firstPaletteLine(todo.Title)
if title == "" || todo.Done {
continue
}
rows = append(rows, paletteTodoPreviewItem{Title: title, Done: todo.Done})
}
return rows
}
func renderPaletteTodoPreviewSection(styles paletteStyles, section paletteTodoPreviewSection, width int, previewLimit int) []string {
lines := []string{styles.statLabel.Render(section.Title)}
if section.Lead != "" {