feat(desktop): auto-restart desktop-managed daemon on version mismatch

When the desktop app starts and finds a running daemon with a different
version, it now restarts it automatically. Only applies to daemons the
desktop app itself started, identified by a PASEO_DESKTOP_MANAGED flag
written into the PID lock file.

Also rewrites resolveStatus() to use the CLI daemon status command
instead of manually parsing the PID file, and surfaces daemonVersion
in the CLI status output from the WebSocket hello message.
This commit is contained in:
Mohamed Boudra
2026-04-03 19:43:56 +07:00
parent 23ffec5072
commit 29037abd54
6 changed files with 81 additions and 128 deletions
@@ -21,6 +21,7 @@ export interface LocalDaemonPidInfo {
hostname?: string;
uid?: number;
listen?: string;
desktopManaged?: boolean;
}
export interface LocalDaemonState {
@@ -173,6 +174,7 @@ function readPidFile(pidPath: string): LocalDaemonPidInfo | null {
: typeof parsed.sockPath === "string"
? parsed.sockPath
: undefined,
desktopManaged: parsed.desktopManaged === true ? true : undefined,
};
} catch {
return null;
@@ -34,6 +34,8 @@ interface DaemonStatus {
daemonNode: string;
cliNode: string;
cliVersion: string;
daemonVersion: string | null;
desktopManaged: boolean;
providers: ProviderBinaryStatus[];
note?: string;
}
@@ -129,6 +131,7 @@ function toStatusRows(status: DaemonStatus): StatusRow[] {
{ key: "Daemon Node", value: status.daemonNode },
{ key: "CLI Node", value: status.cliNode },
{ key: "CLI", value: status.cliVersion },
{ key: "Daemon Version", value: status.daemonVersion ?? "-" },
];
if (status.runningAgents !== null && status.idleAgents !== null) {
@@ -229,6 +232,7 @@ export async function runStatusCommand(
let connectedDaemon: DaemonStatus["connectedDaemon"] = "not_probed";
let runningAgents: number | null = null;
let idleAgents: number | null = null;
let daemonVersion: string | null = null;
let note: string | undefined;
if (!state.running && state.stalePidFile && state.pidInfo) {
@@ -240,6 +244,7 @@ export async function runStatusCommand(
const client = await tryConnectToDaemon({ host, timeout: 1500 });
if (client) {
connectedDaemon = "reachable";
daemonVersion = client.getLastServerInfoMessage()?.version ?? null;
try {
const agentsPayload = await client.fetchAgents({ filter: { includeArchived: true } });
const agents = agentsPayload.entries.map((entry) => entry.agent);
@@ -308,6 +313,8 @@ export async function runStatusCommand(
daemonNode,
cliNode,
cliVersion,
daemonVersion,
desktopManaged: state.pidInfo?.desktopManaged === true,
providers,
note,
};