f459d4e255
Añade opciones de Reload (hot-reload) separadas de Restart (reinicio
completo) en el dashboard, usando el mecanismo SIGHUP implementado en
el issue 0013.
Cambios en pkg/tui/ (capa pura):
- IntentReloadAgent: hot-reload de un agente individual via SIGHUP
- IntentReloadAll: hot-reload de todos los agentes via SIGHUP
- AgentActionOptions: añade "Reload" antes de "Restart" con descripciones
clarificadas ("sin interrumpir los demás" vs "launcher completo")
- ServerMenuOptions (running): añade "Reload All" como primera opción
- executeAction: maneja "Reload" → IntentReloadAgent
- executeServerAction: maneja "Reload All" → IntentReloadAll
- Mensajes de estado diferenciados: "Reload OK — X recargado sin
interrupciones" vs "Restart OK — launcher reiniciado"
Cambios en shell/tui/ (capa impura):
- reloadAgent(id): escribe run/reload.txt + SIGHUP; error si launcher
no está corriendo (no hay fallback a full restart)
- reloadAll(): elimina reload.txt + SIGHUP; error si no está corriendo
- restartAgent(id): restaurado a su comportamiento original de
stop+start completo del launcher
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
137 lines
4.2 KiB
Go
137 lines
4.2 KiB
Go
// 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}
|
|
}
|