// 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 ScreenServer // server-wide process management ScreenTests // test type selection menu ScreenTestOutput // test run output ) // TestKind identifies which test suite to run. type TestKind int const ( TestKindNone TestKind = iota TestKindGo // go test -tags goolm -count=1 ./... TestKindE2E // ./dev-scripts/e2e/run.sh TestKindE2EHead // ./dev-scripts/e2e/run.sh --headed TestKindAll // Go tests + E2E sequential ) // 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 // Unified launcher state LauncherRunning bool LauncherPID int LauncherUptime string LauncherMemory string LauncherCPU string LauncherLogSize string // Test state LastTestKind TestKind // which test to re-run with "r" } // 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 Instances int // number of running instances (>1 means duplicates) 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: "Server", Desc: "Gestionar launcher unificado"}, {Label: "Tests", Desc: "Ejecutar tests"}, {Label: "Quit", Desc: "Salir"}, } } // TestMenuOptions returns the available test types. func TestMenuOptions() []MenuOption { return []MenuOption{ {Label: "Go Tests", Desc: "go test ./..."}, {Label: "E2E Tests", Desc: "Playwright headless"}, {Label: "E2E Tests (headed)", Desc: "Playwright con browser"}, {Label: "All Tests", Desc: "Go + E2E secuencial"}, } } // ServerMenuOptions returns the available server-wide actions. func ServerMenuOptions(running bool) []MenuOption { if running { return []MenuOption{ {Label: "Reload All", Desc: "Hot-reload de todos los agentes (SIGHUP)"}, {Label: "Stop", Desc: "Detener el launcher"}, {Label: "Restart", Desc: "Reiniciar el launcher"}, {Label: "Kill", Desc: "SIGKILL forzado"}, {Label: "Rebuild & Restart", Desc: "Build + reiniciar"}, {Label: "Logs", Desc: "Ver log del launcher"}, {Label: "Tests", Desc: "Ir a pantalla de tests"}, } } return []MenuOption{ {Label: "Start", Desc: "Iniciar el launcher unificado"}, {Label: "Rebuild & Restart", Desc: "Build + iniciar"}, {Label: "Tests", Desc: "Ir a pantalla de tests"}, } } // AgentActionOptions returns the available actions based on agent state. func AgentActionOptions(enabled bool) []MenuOption { if enabled { return []MenuOption{ {Label: "Reload", Desc: "Hot-reload este agente (SIGHUP, sin interrumpir los demás)"}, {Label: "Restart", Desc: "Reiniciar el launcher completo (todos los agentes)"}, {Label: "Disable", Desc: "Desactivar agente (requiere restart)"}, {Label: "Logs", Desc: "Ver log del launcher"}, } } return []MenuOption{ {Label: "Reload", Desc: "Hot-reload este agente (SIGHUP, sin interrumpir los demás)"}, {Label: "Restart", Desc: "Reiniciar el launcher completo (todos los agentes)"}, {Label: "Enable", Desc: "Activar agente (requiere restart)"}, {Label: "Logs", Desc: "Ver log del launcher"}, } } // InitialModel returns the starting state. func InitialModel() Model { return Model{Screen: ScreenMain} }