feat: add bubbletea TUI dashboard for bot server management
Implementa un dashboard interactivo con bubbletea siguiendo el patrón pure core / impure shell del proyecto: - pkg/tui/ (PURE): Model, Update, View — solo fmt y strings, cero I/O. Update produce Intent[] (datos puros) en vez de side effects. - shell/tui/ (IMPURE): Adapter convierte Intent[] en tea.Cmd[] con I/O real (process management, /proc stats, log tail). - cmd/dashboard/ (composición): Bridge conecta pure Update con shell Adapter usando la Elm Architecture de bubbletea. Pantallas: Main Menu → Agent List → Agent Actions (start/stop/restart/kill) → Logs. Navegación: flechas ↑↓, Enter seleccionar, 0 volver, q salir. Dependencias añadidas: bubbletea, lipgloss. Actualiza .gitignore para anclar binarios a raíz (/agentctl, /dashboard). Documenta nuevos scripts en CLAUDE.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
// Package tui defines the pure TUI model, messages, update, and view.
|
||||
// Zero I/O, zero side effects. Only data transformations.
|
||||
package tui
|
||||
|
||||
// Screen identifies the current TUI screen.
|
||||
type Screen int
|
||||
|
||||
const (
|
||||
ScreenMain Screen = iota
|
||||
ScreenAgentList // list all agents with status
|
||||
ScreenAgentActions // actions for a selected agent
|
||||
ScreenLogs // tail log output
|
||||
)
|
||||
|
||||
// Model is the complete TUI state — pure data.
|
||||
type Model struct {
|
||||
Screen Screen
|
||||
Agents []AgentView
|
||||
Cursor int
|
||||
Selected *AgentView // nil when no agent selected
|
||||
LogLines []string
|
||||
LogScroll int
|
||||
StatusMsg string // flash message ("Started OK", "Error: ...")
|
||||
WindowWidth int
|
||||
WindowHeight int
|
||||
}
|
||||
|
||||
// AgentView is a pre-formatted projection of an agent for display.
|
||||
type AgentView struct {
|
||||
ID string
|
||||
Name string
|
||||
Version string
|
||||
Desc string
|
||||
Enabled bool
|
||||
Running bool
|
||||
PID int
|
||||
Uptime string // formatted: "2h 15m"
|
||||
Memory string // formatted: "42 MB"
|
||||
CPU string // formatted: "1.2%"
|
||||
LogSize string // formatted: "350 KB"
|
||||
}
|
||||
|
||||
// MenuOption represents a selectable menu item.
|
||||
type MenuOption struct {
|
||||
Label string
|
||||
Desc string
|
||||
}
|
||||
|
||||
// MainMenuOptions returns the options for the main screen.
|
||||
func MainMenuOptions() []MenuOption {
|
||||
return []MenuOption{
|
||||
{Label: "Agents", Desc: "Gestionar agentes"},
|
||||
{Label: "Quit", Desc: "Salir"},
|
||||
}
|
||||
}
|
||||
|
||||
// AgentActionOptions returns the available actions based on agent state.
|
||||
func AgentActionOptions(running bool) []MenuOption {
|
||||
if running {
|
||||
return []MenuOption{
|
||||
{Label: "Stop", Desc: "Detener el agente"},
|
||||
{Label: "Restart", Desc: "Reiniciar"},
|
||||
{Label: "Kill", Desc: "SIGKILL forzado"},
|
||||
{Label: "Logs", Desc: "Ver log del agente"},
|
||||
}
|
||||
}
|
||||
return []MenuOption{
|
||||
{Label: "Start", Desc: "Iniciar el agente"},
|
||||
{Label: "Logs", Desc: "Ver log del agente"},
|
||||
}
|
||||
}
|
||||
|
||||
// InitialModel returns the starting state.
|
||||
func InitialModel() Model {
|
||||
return Model{Screen: ScreenMain}
|
||||
}
|
||||
Reference in New Issue
Block a user