feat: controles de hot-reload por agente en el dashboard TUI
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>
This commit is contained in:
+47
-14
@@ -39,6 +39,12 @@ func (a *Adapter) RunIntent(intent puretui.Intent) tea.Cmd {
|
||||
case puretui.IntentDisableAgent:
|
||||
return a.disableAgent(intent.AgentID)
|
||||
|
||||
case puretui.IntentReloadAgent:
|
||||
return a.reloadAgent(intent.AgentID)
|
||||
|
||||
case puretui.IntentReloadAll:
|
||||
return a.reloadAll()
|
||||
|
||||
case puretui.IntentRestartAgent:
|
||||
return a.restartAgent(intent.AgentID)
|
||||
|
||||
@@ -140,30 +146,57 @@ func (a *Adapter) disableAgent(id string) tea.Cmd {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Adapter) restartAgent(id string) tea.Cmd {
|
||||
// reloadAgent hot-reloads a single agent via SIGHUP without stopping the launcher.
|
||||
func (a *Adapter) reloadAgent(id string) tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
pid := a.mgr.UnifiedPID()
|
||||
if pid <= 0 {
|
||||
// Launcher not running — fall back to full restart.
|
||||
_ = a.mgr.StopUnified()
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
err := a.mgr.StartUnified()
|
||||
if err == nil {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
return puretui.MsgActionDone{AgentID: id, Action: "Restart", Err: err}
|
||||
return puretui.MsgActionDone{AgentID: id, Action: "Reload",
|
||||
Err: fmt.Errorf("el launcher no está corriendo")}
|
||||
}
|
||||
|
||||
// Launcher is running — write target and send SIGHUP for hot-reload.
|
||||
if id != "" {
|
||||
_ = os.WriteFile("run/reload.txt", []byte(id), 0o644)
|
||||
if err := os.WriteFile("run/reload.txt", []byte(id), 0o644); err != nil {
|
||||
return puretui.MsgActionDone{AgentID: id, Action: "Reload", Err: err}
|
||||
}
|
||||
}
|
||||
err := syscall.Kill(pid, syscall.SIGHUP)
|
||||
if err != nil {
|
||||
return puretui.MsgActionDone{AgentID: id, Action: "Restart", Err: err}
|
||||
return puretui.MsgActionDone{AgentID: id, Action: "Reload", Err: err}
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
return puretui.MsgActionDone{AgentID: id, Action: "Restart", Err: nil}
|
||||
return puretui.MsgActionDone{AgentID: id, Action: "Reload", Err: nil}
|
||||
}
|
||||
}
|
||||
|
||||
// reloadAll hot-reloads all agents via SIGHUP (no reload.txt → reload all).
|
||||
func (a *Adapter) reloadAll() tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
pid := a.mgr.UnifiedPID()
|
||||
if pid <= 0 {
|
||||
return puretui.MsgServerActionDone{Action: "Reload All",
|
||||
Err: fmt.Errorf("el launcher no está corriendo")}
|
||||
}
|
||||
// Remove stale reload.txt so the launcher reloads all agents.
|
||||
_ = os.Remove("run/reload.txt")
|
||||
err := syscall.Kill(pid, syscall.SIGHUP)
|
||||
if err != nil {
|
||||
return puretui.MsgServerActionDone{Action: "Reload All", Err: err}
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
return puretui.MsgServerActionDone{Action: "Reload All", Err: nil}
|
||||
}
|
||||
}
|
||||
|
||||
// restartAgent stops and restarts the whole launcher (full restart, all agents).
|
||||
func (a *Adapter) restartAgent(id string) tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
_ = a.mgr.StopUnified()
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
err := a.mgr.StartUnified()
|
||||
if err == nil {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
return puretui.MsgActionDone{AgentID: id, Action: "Restart", Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user