From 465f8aaa14c32b49d56dcc75833554b18f9d4600 Mon Sep 17 00:00:00 2001 From: Junebugg1214 <82672745+Junebugg1214@users.noreply.github.com> Date: Fri, 20 Mar 2026 23:54:45 -0400 Subject: [PATCH] Lazy-load daemon status adapters --- src/commands/status.daemon.ts | 88 ++++++++++++++++++++++++-- src/commands/status.service-summary.ts | 17 ++++- 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/src/commands/status.daemon.ts b/src/commands/status.daemon.ts index dcf5487e8ce..bfb3465948b 100644 --- a/src/commands/status.daemon.ts +++ b/src/commands/status.daemon.ts @@ -1,7 +1,16 @@ -import { resolveNodeService } from "../daemon/node-service.js"; -import { resolveGatewayService } from "../daemon/service.js"; +import { + NODE_SERVICE_KIND, + NODE_SERVICE_MARKER, + NODE_WINDOWS_TASK_SCRIPT_NAME, + resolveNodeLaunchAgentLabel, + resolveNodeSystemdServiceName, + resolveNodeWindowsTaskName, +} from "../daemon/constants.js"; import { formatDaemonRuntimeShort } from "./status.format.js"; -import { readServiceStatusSummary } from "./status.service-summary.js"; +import { + readServiceStatusSummary, + type GatewayServiceStatusReader, +} from "./status.service-summary.js"; type DaemonStatusSummary = { label: string; @@ -12,10 +21,81 @@ type DaemonStatusSummary = { runtimeShort: string | null; }; +function withNodeServiceEnv( + env: Record, +): Record { + return { + ...env, + OPENCLAW_LAUNCHD_LABEL: resolveNodeLaunchAgentLabel(), + OPENCLAW_SYSTEMD_UNIT: resolveNodeSystemdServiceName(), + OPENCLAW_WINDOWS_TASK_NAME: resolveNodeWindowsTaskName(), + OPENCLAW_TASK_SCRIPT_NAME: NODE_WINDOWS_TASK_SCRIPT_NAME, + OPENCLAW_LOG_PREFIX: "node", + OPENCLAW_SERVICE_MARKER: NODE_SERVICE_MARKER, + OPENCLAW_SERVICE_KIND: NODE_SERVICE_KIND, + }; +} + +async function loadGatewayServiceStatusReader(): Promise { + if (process.platform === "darwin") { + const launchd = await import("../daemon/launchd.js"); + return { + label: "LaunchAgent", + loadedText: "loaded", + notLoadedText: "not loaded", + isLoaded: launchd.isLaunchAgentLoaded, + readCommand: launchd.readLaunchAgentProgramArguments, + readRuntime: launchd.readLaunchAgentRuntime, + }; + } + if (process.platform === "linux") { + const systemd = await import("../daemon/systemd.js"); + return { + label: "systemd", + loadedText: "enabled", + notLoadedText: "disabled", + isLoaded: systemd.isSystemdServiceEnabled, + readCommand: systemd.readSystemdServiceExecStart, + readRuntime: systemd.readSystemdServiceRuntime, + }; + } + if (process.platform === "win32") { + const schtasks = await import("../daemon/schtasks.js"); + return { + label: "Scheduled Task", + loadedText: "registered", + notLoadedText: "missing", + isLoaded: schtasks.isScheduledTaskInstalled, + readCommand: schtasks.readScheduledTaskCommand, + readRuntime: schtasks.readScheduledTaskRuntime, + }; + } + throw new Error(`Gateway service install not supported on ${process.platform}`); +} + +async function loadNodeServiceStatusReader(): Promise { + const base = await loadGatewayServiceStatusReader(); + return { + ...base, + isLoaded: async (args) => { + return base.isLoaded({ env: withNodeServiceEnv(args.env ?? {}) }); + }, + readCommand: async (env) => { + return base.readCommand(withNodeServiceEnv(env)); + }, + readRuntime: async (env) => { + return base.readRuntime(withNodeServiceEnv(env)); + }, + }; +} + async function buildDaemonStatusSummary( serviceLabel: "gateway" | "node", ): Promise { - const service = serviceLabel === "gateway" ? resolveGatewayService() : resolveNodeService(); + const service = + serviceLabel === "gateway" + ? await loadGatewayServiceStatusReader() + : await loadNodeServiceStatusReader(); const fallbackLabel = serviceLabel === "gateway" ? "Daemon" : "Node"; const summary = await readServiceStatusSummary(service, fallbackLabel); return { diff --git a/src/commands/status.service-summary.ts b/src/commands/status.service-summary.ts index cc366c2c7ba..313480b6c91 100644 --- a/src/commands/status.service-summary.ts +++ b/src/commands/status.service-summary.ts @@ -1,5 +1,18 @@ import type { GatewayServiceRuntime } from "../daemon/service-runtime.js"; -import type { GatewayService } from "../daemon/service.js"; +import type { + GatewayServiceCommandConfig, + GatewayServiceEnv, + GatewayServiceEnvArgs, +} from "../daemon/service-types.js"; + +export type GatewayServiceStatusReader = { + label: string; + loadedText: string; + notLoadedText: string; + isLoaded: (args: GatewayServiceEnvArgs) => Promise; + readCommand: (env: GatewayServiceEnv) => Promise; + readRuntime: (env: GatewayServiceEnv) => Promise; +}; export type ServiceStatusSummary = { label: string; @@ -12,7 +25,7 @@ export type ServiceStatusSummary = { }; export async function readServiceStatusSummary( - service: GatewayService, + service: GatewayServiceStatusReader, fallbackLabel: string, ): Promise { try {