From 8ec9f39b6d6d41c14c01cd31f75e14df063fc1fe Mon Sep 17 00:00:00 2001 From: Enmanuel Date: Sun, 8 Mar 2026 18:42:38 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20agentctl=20reload=20=E2=80=94=20subcoma?= =?UTF-8?q?ndo=20de=20hot-reload=20via=20SIGHUP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nuevo subcomando: agentctl reload [agent-id] - Sin argumento: elimina run/reload.txt y envía SIGHUP → todos los agentes se recargan. - Con agent-id: escribe run/reload.txt con el ID y envía SIGHUP → solo ese agente se recarga. Si el launcher no está corriendo, muestra error claro. Co-Authored-By: Claude Sonnet 4.6 --- cmd/agentctl/main.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/cmd/agentctl/main.go b/cmd/agentctl/main.go index cd3da10..1385f71 100644 --- a/cmd/agentctl/main.go +++ b/cmd/agentctl/main.go @@ -14,6 +14,7 @@ import ( "fmt" "os" "strings" + "syscall" "github.com/spf13/cobra" @@ -47,6 +48,7 @@ func main() { listCmd(mgr), startCmd(mgr, &binPath), stopCmd(mgr), + reloadCmd(mgr), removeCmd(mgr), avatarCmd(), displaynameCmd(), @@ -171,6 +173,48 @@ func stopCmd(mgr *process.Manager) *cobra.Command { } } +// ── reload ──────────────────────────────────────────────────────────────── + +func reloadCmd(mgr *process.Manager) *cobra.Command { + return &cobra.Command{ + Use: "reload [agent-id]", + Short: "Hot-reload an agent (or all agents) without stopping the launcher", + Long: `Sends SIGHUP to the running launcher, which triggers a hot-reload. +If an agent-id is given, only that agent is reloaded. +If no agent-id is given, all agents are reloaded. + +The launcher must be running. Use 'agentctl start' first if needed.`, + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + pid := mgr.UnifiedPID() + if pid <= 0 { + return fmt.Errorf("launcher is not running") + } + + target := "" + if len(args) == 1 { + target = args[0] + } + + if target != "" { + if err := os.WriteFile("run/reload.txt", []byte(target), 0o644); err != nil { + return fmt.Errorf("write reload target: %w", err) + } + fmt.Printf("reload %-20s sending SIGHUP to PID %d\n", target, pid) + } else { + // Remove any stale reload.txt so SIGHUP reloads all agents. + _ = os.Remove("run/reload.txt") + fmt.Printf("reload %-20s sending SIGHUP to PID %d\n", "(all)", pid) + } + + if err := syscall.Kill(pid, syscall.SIGHUP); err != nil { + return fmt.Errorf("kill -HUP %d: %w", pid, err) + } + return nil + }, + } +} + // ── remove ──────────────────────────────────────────────────────────────── func removeCmd(mgr *process.Manager) *cobra.Command {