feat: update dashboard and process manager for unified launcher
Actualiza el dashboard TUI y el process manager para el modelo de launcher unificado donde todos los agentes corren en un solo proceso. Dashboard (pkg/tui): - model.go: campos de estado del launcher (PID, uptime, memory, CPU, log size) - model.go: ServerMenuOptions(running) contextual, AgentActionOptions(enabled) - messages.go: MsgAgentsLoaded incluye estado del launcher, MsgServerActionDone/MsgRebuildDone simplificados - update.go: intents nuevos (Enable/Disable agent, Start/Stop/Restart/Kill launcher) - view.go: vista de servidor muestra stats del launcher, agentes muestran enabled/disabled Shell adapter (shell/tui): - adapter.go: reescrito para usar métodos unificados (StartUnified, StopUnified, ToggleEnabled, StatusAllUnified, UnifiedStats, UnifiedLogTail) Process manager (shell/process): - manager.go: métodos StartUnified, StopUnified, KillUnified, IsUnifiedRunning, UnifiedPID, UnifiedStats, UnifiedLogTail, StatusAllUnified, ToggleEnabled Los agentes ya no se inician/detienen individualmente desde el dashboard. Se habilitan/deshabilitan en config y se reinicia el launcher para aplicar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+68
-59
@@ -6,20 +6,20 @@ import "fmt"
|
||||
type IntentKind string
|
||||
|
||||
const (
|
||||
IntentLoadAgents IntentKind = "load_agents"
|
||||
IntentStartAgent IntentKind = "start_agent"
|
||||
IntentStopAgent IntentKind = "stop_agent"
|
||||
IntentKillAgent IntentKind = "kill_agent"
|
||||
IntentRestartAgent IntentKind = "restart_agent"
|
||||
IntentLoadLogs IntentKind = "load_logs"
|
||||
IntentTick IntentKind = "tick"
|
||||
IntentQuit IntentKind = "quit"
|
||||
IntentLoadAgents IntentKind = "load_agents"
|
||||
IntentLoadLogs IntentKind = "load_logs"
|
||||
IntentTick IntentKind = "tick"
|
||||
IntentQuit IntentKind = "quit"
|
||||
|
||||
// Server-wide bulk operations
|
||||
IntentStartAll IntentKind = "start_all"
|
||||
IntentStopAll IntentKind = "stop_all"
|
||||
IntentRestartAll IntentKind = "restart_all"
|
||||
IntentKillAll IntentKind = "kill_all"
|
||||
// Agent-level
|
||||
IntentEnableAgent IntentKind = "enable_agent"
|
||||
IntentDisableAgent IntentKind = "disable_agent"
|
||||
|
||||
// Unified launcher operations
|
||||
IntentStartLauncher IntentKind = "start_launcher"
|
||||
IntentStopLauncher IntentKind = "stop_launcher"
|
||||
IntentRestartLauncher IntentKind = "restart_launcher"
|
||||
IntentKillLauncher IntentKind = "kill_launcher"
|
||||
IntentRebuildRestart IntentKind = "rebuild_restart"
|
||||
)
|
||||
|
||||
@@ -32,7 +32,7 @@ type Intent struct {
|
||||
// KeyMsg is the pure representation of a key press.
|
||||
// The bridge layer converts tea.KeyMsg into this.
|
||||
type KeyMsg struct {
|
||||
Str string // "up", "down", "enter", "0", "q", "r", etc.
|
||||
Str string // "up", "down", "enter", "0", "q", "r", etc.
|
||||
}
|
||||
|
||||
// WindowSizeMsg carries terminal dimensions.
|
||||
@@ -52,7 +52,12 @@ func Update(model Model, msg interface{}) (Model, []Intent) {
|
||||
|
||||
case MsgAgentsLoaded:
|
||||
model.Agents = m.Agents
|
||||
// Clamp cursor only on screens that use the agent list
|
||||
model.LauncherRunning = m.LauncherRunning
|
||||
model.LauncherPID = m.LauncherPID
|
||||
model.LauncherUptime = m.LauncherUptime
|
||||
model.LauncherMemory = m.LauncherMemory
|
||||
model.LauncherCPU = m.LauncherCPU
|
||||
model.LauncherLogSize = m.LauncherLogSize
|
||||
if model.Screen == ScreenAgentList {
|
||||
if model.Cursor >= len(model.Agents) && len(model.Agents) > 0 {
|
||||
model.Cursor = len(model.Agents) - 1
|
||||
@@ -64,25 +69,27 @@ func Update(model Model, msg interface{}) (Model, []Intent) {
|
||||
if m.Err != nil {
|
||||
model.StatusMsg = fmt.Sprintf("Error: %s %s: %v", m.Action, m.AgentID, m.Err)
|
||||
} else {
|
||||
model.StatusMsg = fmt.Sprintf("%s %s OK", m.Action, m.AgentID)
|
||||
model.StatusMsg = fmt.Sprintf("%s %s OK — restart launcher to apply", m.Action, m.AgentID)
|
||||
}
|
||||
return model, []Intent{{Kind: IntentLoadAgents}}
|
||||
|
||||
case MsgServerActionDone:
|
||||
if m.Err != nil {
|
||||
model.StatusMsg = fmt.Sprintf("Error: %s: %v", m.Action, m.Err)
|
||||
} else {
|
||||
model.StatusMsg = fmt.Sprintf("%s OK", m.Action)
|
||||
}
|
||||
return model, []Intent{{Kind: IntentLoadAgents}}
|
||||
|
||||
case MsgRebuildDone:
|
||||
if !m.BuildOK {
|
||||
model.StatusMsg = fmt.Sprintf("Build failed: %s", m.BuildLog)
|
||||
} else if m.Failed > 0 {
|
||||
model.StatusMsg = fmt.Sprintf("Built OK, %d/%d agents failed to restart", m.Failed, m.Restarted+m.Failed)
|
||||
} else if m.Err != nil {
|
||||
model.StatusMsg = fmt.Sprintf("Built OK, start failed: %v", m.Err)
|
||||
} else if m.Started {
|
||||
model.StatusMsg = "Built OK, launcher started"
|
||||
} else {
|
||||
model.StatusMsg = fmt.Sprintf("Built OK, %d agents restarted", m.Restarted)
|
||||
}
|
||||
return model, []Intent{{Kind: IntentLoadAgents}}
|
||||
|
||||
case MsgServerActionDone:
|
||||
if m.Failed == 0 {
|
||||
model.StatusMsg = fmt.Sprintf("%s: %d agents OK", m.Action, m.Total)
|
||||
} else {
|
||||
model.StatusMsg = fmt.Sprintf("%s: %d/%d failed", m.Action, m.Failed, m.Total)
|
||||
model.StatusMsg = "Built OK"
|
||||
}
|
||||
return model, []Intent{{Kind: IntentLoadAgents}}
|
||||
|
||||
@@ -102,7 +109,6 @@ func Update(model Model, msg interface{}) (Model, []Intent) {
|
||||
}
|
||||
|
||||
func updateKey(model Model, key KeyMsg) (Model, []Intent) {
|
||||
// Global quit
|
||||
if key.Str == "q" && model.Screen == ScreenMain {
|
||||
return model, []Intent{{Kind: IntentQuit}}
|
||||
}
|
||||
@@ -178,7 +184,7 @@ func updateAgentActions(model Model, key KeyMsg) (Model, []Intent) {
|
||||
return model, nil
|
||||
}
|
||||
|
||||
opts := AgentActionOptions(model.Selected.Running)
|
||||
opts := AgentActionOptions(model.Selected.Enabled)
|
||||
|
||||
switch key.Str {
|
||||
case "0":
|
||||
@@ -202,18 +208,12 @@ func updateAgentActions(model Model, key KeyMsg) (Model, []Intent) {
|
||||
func executeAction(model Model, action string) (Model, []Intent) {
|
||||
id := model.Selected.ID
|
||||
switch action {
|
||||
case "Start":
|
||||
model.StatusMsg = "Starting " + id + "..."
|
||||
return model, []Intent{{Kind: IntentStartAgent, AgentID: id}}
|
||||
case "Stop":
|
||||
model.StatusMsg = "Stopping " + id + "..."
|
||||
return model, []Intent{{Kind: IntentStopAgent, AgentID: id}}
|
||||
case "Restart":
|
||||
model.StatusMsg = "Restarting " + id + "..."
|
||||
return model, []Intent{{Kind: IntentRestartAgent, AgentID: id}}
|
||||
case "Kill":
|
||||
model.StatusMsg = "Killing " + id + "..."
|
||||
return model, []Intent{{Kind: IntentKillAgent, AgentID: id}}
|
||||
case "Enable":
|
||||
model.StatusMsg = "Enabling " + id + "..."
|
||||
return model, []Intent{{Kind: IntentEnableAgent, AgentID: id}}
|
||||
case "Disable":
|
||||
model.StatusMsg = "Disabling " + id + "..."
|
||||
return model, []Intent{{Kind: IntentDisableAgent, AgentID: id}}
|
||||
case "Logs":
|
||||
model.Screen = ScreenLogs
|
||||
model.LogLines = nil
|
||||
@@ -227,7 +227,11 @@ func executeAction(model Model, action string) (Model, []Intent) {
|
||||
func updateLogs(model Model, key KeyMsg) (Model, []Intent) {
|
||||
switch key.Str {
|
||||
case "0":
|
||||
model.Screen = ScreenAgentActions
|
||||
if model.Selected != nil {
|
||||
model.Screen = ScreenAgentActions
|
||||
} else {
|
||||
model.Screen = ScreenServer
|
||||
}
|
||||
model.Cursor = 0
|
||||
model.LogLines = nil
|
||||
model.LogScroll = 0
|
||||
@@ -237,15 +241,13 @@ func updateLogs(model Model, key KeyMsg) (Model, []Intent) {
|
||||
maxScroll := max(0, len(model.LogLines)-visibleLogLines(model))
|
||||
model.LogScroll = min(model.LogScroll+1, maxScroll)
|
||||
case "r":
|
||||
if model.Selected != nil {
|
||||
return model, []Intent{{Kind: IntentLoadLogs, AgentID: model.Selected.ID}}
|
||||
}
|
||||
return model, []Intent{{Kind: IntentLoadLogs}}
|
||||
}
|
||||
return model, nil
|
||||
}
|
||||
|
||||
func updateServerScreen(model Model, key KeyMsg) (Model, []Intent) {
|
||||
opts := ServerMenuOptions()
|
||||
opts := ServerMenuOptions(model.LauncherRunning)
|
||||
|
||||
switch key.Str {
|
||||
case "0":
|
||||
@@ -266,21 +268,28 @@ func updateServerScreen(model Model, key KeyMsg) (Model, []Intent) {
|
||||
|
||||
func executeServerAction(model Model, action string) (Model, []Intent) {
|
||||
switch action {
|
||||
case "Start All":
|
||||
model.StatusMsg = "Starting all agents..."
|
||||
return model, []Intent{{Kind: IntentStartAll}}
|
||||
case "Stop All":
|
||||
model.StatusMsg = "Stopping all agents..."
|
||||
return model, []Intent{{Kind: IntentStopAll}}
|
||||
case "Restart All":
|
||||
model.StatusMsg = "Restarting all agents..."
|
||||
return model, []Intent{{Kind: IntentRestartAll}}
|
||||
case "Kill All":
|
||||
model.StatusMsg = "Killing all agents..."
|
||||
return model, []Intent{{Kind: IntentKillAll}}
|
||||
case "Start":
|
||||
model.StatusMsg = "Starting launcher..."
|
||||
return model, []Intent{{Kind: IntentStartLauncher}}
|
||||
case "Stop":
|
||||
model.StatusMsg = "Stopping launcher..."
|
||||
return model, []Intent{{Kind: IntentStopLauncher}}
|
||||
case "Restart":
|
||||
model.StatusMsg = "Restarting launcher..."
|
||||
return model, []Intent{{Kind: IntentRestartLauncher}}
|
||||
case "Kill":
|
||||
model.StatusMsg = "Killing launcher..."
|
||||
return model, []Intent{{Kind: IntentKillLauncher}}
|
||||
case "Rebuild & Restart":
|
||||
model.StatusMsg = "Building & restarting..."
|
||||
return model, []Intent{{Kind: IntentRebuildRestart}}
|
||||
case "Logs":
|
||||
model.Screen = ScreenLogs
|
||||
model.LogLines = nil
|
||||
model.LogScroll = 0
|
||||
model.Selected = nil
|
||||
model.Cursor = 0
|
||||
return model, []Intent{{Kind: IntentLoadLogs}}
|
||||
}
|
||||
return model, nil
|
||||
}
|
||||
@@ -288,7 +297,7 @@ func executeServerAction(model Model, action string) (Model, []Intent) {
|
||||
// ── pure helpers ─────────────────────────────────────────────────────────
|
||||
|
||||
func visibleLogLines(m Model) int {
|
||||
lines := m.WindowHeight - 6 // header + footer
|
||||
lines := m.WindowHeight - 6
|
||||
if lines < 5 {
|
||||
return 5
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user