From b61a907bac09a7649ca3f6d850e771b3b75c7015 Mon Sep 17 00:00:00 2001 From: soryu Date: Thu, 22 Jan 2026 01:26:53 +0000 Subject: Add daemon restart feature from settings (#18) * Add daemon restart feature from settings This adds the ability to restart a connected daemon from the settings page. The feature includes: - Backend: RestartDaemon command added to DaemonCommand enum - Backend: New POST /api/v1/mesh/daemons/{id}/restart endpoint - Backend: Daemon gracefully shuts down tasks and exits with code 42 (can be used by process managers like systemd to detect restart requests) - Frontend: restartDaemon() API function - Frontend: Restart button in Connected Daemons section of settings - Frontend: Confirmation dialog before restart to prevent accidental restarts When a daemon receives the restart command, it: 1. Gracefully shuts down all running Claude processes (5s timeout) 2. Exits with code 42 to signal restart requested 3. The daemon can be restarted by a process manager or manually Co-Authored-By: Claude Opus 4.5 --- makima/frontend/src/routes/settings.tsx | 79 ++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 11 deletions(-) (limited to 'makima/frontend/src/routes') diff --git a/makima/frontend/src/routes/settings.tsx b/makima/frontend/src/routes/settings.tsx index d3f4c1b..b93ecbc 100644 --- a/makima/frontend/src/routes/settings.tsx +++ b/makima/frontend/src/routes/settings.tsx @@ -11,6 +11,7 @@ import { changeEmail, deleteAccount, listDaemons, + restartDaemon, listRepositoryHistory, deleteRepositoryHistory, type ApiKeyInfo, @@ -306,6 +307,8 @@ export default function SettingsPage() { const [daemons, setDaemons] = useState([]); const [daemonsLoading, setDaemonsLoading] = useState(true); const [daemonsError, setDaemonsError] = useState(null); + const [restartingDaemonId, setRestartingDaemonId] = useState(null); + const [restartConfirmDaemonId, setRestartConfirmDaemonId] = useState(null); // Repository history state const [repoHistory, setRepoHistory] = useState([]); @@ -376,6 +379,23 @@ export default function SettingsPage() { } }; + const handleRestartDaemon = async (id: string) => { + try { + setRestartingDaemonId(id); + setDaemonsError(null); + await restartDaemon(id); + // Daemon will restart, so refresh the list after a short delay + setTimeout(() => { + loadDaemons(); + }, 2000); + } catch (err) { + setDaemonsError(err instanceof Error ? err.message : "Failed to restart daemon"); + } finally { + setRestartingDaemonId(null); + setRestartConfirmDaemonId(null); + } + }; + const handleCreate = async () => { try { setActionLoading(true); @@ -687,17 +707,19 @@ export default function SettingsPage() { {daemon.hostname || "Unknown Host"} - - {daemon.status} - +
+ + {daemon.status} + +
@@ -721,6 +743,41 @@ export default function SettingsPage() {
)}
+ {/* Restart Section */} + {daemon.status === "connected" && ( +
+ {restartConfirmDaemonId === daemon.id ? ( +
+ + Restart daemon? Running tasks will be interrupted. + +
+ + +
+
+ ) : ( + + )} +
+ )} ))} -- cgit v1.2.3