feat(cli): distinguish local and connected daemon status

This commit is contained in:
Mohamed Boudra
2026-03-28 00:31:18 +07:00
parent bb9e181c20
commit a2ab0af3f1
+55 -24
View File
@@ -15,7 +15,8 @@ interface ProviderBinaryStatus {
interface DaemonStatus { interface DaemonStatus {
serverId: string | null; serverId: string | null;
status: "running" | "stopped" | "unresponsive"; localDaemon: "running" | "stopped" | "stale_pid" | "unresponsive";
connectedDaemon: "reachable" | "unreachable" | "not_probed";
home: string; home: string;
listen: string; listen: string;
hostname: string | null; hostname: string | null;
@@ -85,11 +86,16 @@ function createStatusSchema(status: DaemonStatus): OutputSchema<StatusRow> {
header: "VALUE", header: "VALUE",
field: "value", field: "value",
color: (_, item) => { color: (_, item) => {
if (item.key === "Status") { if (item.key === "Local Daemon") {
if (item.value === "running") return "green"; if (item.value === "running") return "green";
if (item.value === "unresponsive") return "yellow"; if (item.value === "unresponsive") return "yellow";
return "red"; return "red";
} }
if (item.key === "Connected Daemon") {
if (item.value === "reachable") return "green";
if (item.value === "not_probed") return "yellow";
return "red";
}
if (item.key.startsWith(" ")) { if (item.key.startsWith(" ")) {
if (item.value === "not found") return "red"; if (item.value === "not found") return "red";
if (item.value.endsWith("(--version failed)")) return "yellow"; if (item.value.endsWith("(--version failed)")) return "yellow";
@@ -106,7 +112,8 @@ function createStatusSchema(status: DaemonStatus): OutputSchema<StatusRow> {
function toStatusRows(status: DaemonStatus): StatusRow[] { function toStatusRows(status: DaemonStatus): StatusRow[] {
const rows: StatusRow[] = [ const rows: StatusRow[] = [
{ key: "Server ID", value: status.serverId ?? "-" }, { key: "Server ID", value: status.serverId ?? "-" },
{ key: "Status", value: status.status }, { key: "Local Daemon", value: status.localDaemon },
{ key: "Connected Daemon", value: status.connectedDaemon },
{ key: "Home", value: status.home }, { key: "Home", value: status.home },
{ key: "Listen", value: status.listen }, { key: "Listen", value: status.listen },
{ key: "Hostname", value: status.hostname ?? "-" }, { key: "Hostname", value: status.hostname ?? "-" },
@@ -199,6 +206,7 @@ export async function runStatusCommand(
): Promise<StatusResult> { ): Promise<StatusResult> {
const home = typeof options.home === "string" ? options.home : undefined; const home = typeof options.home === "string" ? options.home : undefined;
const state = resolveLocalDaemonState({ home }); const state = resolveLocalDaemonState({ home });
const host = resolveTcpHostFromListen(state.listen);
const owner = resolveOwnerLabel(state.pidInfo?.uid, state.pidInfo?.hostname); const owner = resolveOwnerLabel(state.pidInfo?.uid, state.pidInfo?.hostname);
let daemonNode: string; let daemonNode: string;
@@ -211,38 +219,60 @@ export async function runStatusCommand(
daemonNode = "unknown (no PID available)"; daemonNode = "unknown (no PID available)";
} }
const cliNode = process.execPath; const cliNode = process.execPath;
let status: DaemonStatus["status"] = state.running ? "running" : "stopped"; let localDaemon: DaemonStatus["localDaemon"] = state.running ? "running" : "stopped";
let connectedDaemon: DaemonStatus["connectedDaemon"] = "not_probed";
let runningAgents: number | null = null; let runningAgents: number | null = null;
let idleAgents: number | null = null; let idleAgents: number | null = null;
let note: string | undefined; let note: string | undefined;
if (!state.running && state.stalePidFile && state.pidInfo) { if (!state.running && state.stalePidFile && state.pidInfo) {
localDaemon = "stale_pid";
note = `Stale PID file found for PID ${state.pidInfo.pid}`; note = `Stale PID file found for PID ${state.pidInfo.pid}`;
} }
if (state.running) { if (host) {
const host = resolveTcpHostFromListen(state.listen); const client = await tryConnectToDaemon({ host, timeout: 1500 });
if (host) { if (client) {
const client = await tryConnectToDaemon({ host, timeout: 1500 }); connectedDaemon = "reachable";
if (client) { try {
try { const agentsPayload = await client.fetchAgents({ filter: { includeArchived: true } });
const agentsPayload = await client.fetchAgents({ filter: { includeArchived: true } }); const agents = agentsPayload.entries.map((entry) => entry.agent);
const agents = agentsPayload.entries.map((entry) => entry.agent); runningAgents = agents.filter((a) => a.status === "running").length;
runningAgents = agents.filter((a) => a.status === "running").length; idleAgents = agents.filter((a) => a.status === "idle").length;
idleAgents = agents.filter((a) => a.status === "idle").length; if (!state.running) {
} catch { daemonNode = "unknown (API reachable, PID unresolved)";
status = "unresponsive"; note = appendNote(
note = appendNote(note, `Daemon PID is running but API requests to ${host} failed`); note,
} finally { state.pidInfo
await client.close().catch(() => {}); ? `Connected daemon is reachable at ${host} even though local daemon PID ${state.pidInfo.pid} is stale`
: `Connected daemon is reachable at ${host} but no local daemon PID file was found`,
);
} }
} else { } catch {
status = "unresponsive"; if (state.running) {
note = appendNote(note, `Daemon PID is running but websocket at ${host} is not reachable`); localDaemon = "unresponsive";
}
note = appendNote(
note,
state.running
? `Local daemon PID is running but API requests to ${host} failed`
: `Connected daemon websocket is reachable at ${host} but fetch_agents failed`,
);
} finally {
await client.close().catch(() => {});
} }
} else if (state.running) {
connectedDaemon = "unreachable";
localDaemon = "unresponsive";
note = appendNote(
note,
`Local daemon PID is running but websocket at ${host} is not reachable`,
);
} else { } else {
note = appendNote(note, "Daemon is configured for unix socket listen; API probe skipped"); connectedDaemon = "unreachable";
} }
} else {
note = appendNote(note, "Daemon is configured for unix socket listen; API probe skipped");
} }
const cliVersion = resolveCliVersion(); const cliVersion = resolveCliVersion();
@@ -258,7 +288,8 @@ export async function runStatusCommand(
const daemonStatus: DaemonStatus = { const daemonStatus: DaemonStatus = {
serverId, serverId,
status, localDaemon,
connectedDaemon,
home: state.home, home: state.home,
listen: state.listen, listen: state.listen,
hostname: state.pidInfo?.hostname ?? null, hostname: state.pidInfo?.hostname ?? null,