From 0dbc51aa55bd9fa9f174a15d58d5077673340fe3 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 16 Feb 2026 00:36:43 +0000 Subject: [PATCH] refactor(daemon): share service description resolve --- src/daemon/constants.test.ts | 21 +++++++++++++++++++++ src/daemon/constants.ts | 14 ++++++++++++++ src/daemon/launchd.ts | 9 ++------- src/daemon/schtasks.ts | 9 ++------- src/daemon/systemd.ts | 8 ++------ 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/daemon/constants.test.ts b/src/daemon/constants.test.ts index c215ae1a8..4350ae76c 100644 --- a/src/daemon/constants.test.ts +++ b/src/daemon/constants.test.ts @@ -6,6 +6,7 @@ import { GATEWAY_WINDOWS_TASK_NAME, resolveGatewayLaunchAgentLabel, resolveGatewayProfileSuffix, + resolveGatewayServiceDescription, resolveGatewaySystemdServiceName, resolveGatewayWindowsTaskName, } from "./constants.js"; @@ -196,3 +197,23 @@ describe("formatGatewayServiceDescription", () => { ); }); }); + +describe("resolveGatewayServiceDescription", () => { + it("prefers explicit description override", () => { + expect( + resolveGatewayServiceDescription({ + env: { OPENCLAW_PROFILE: "work", OPENCLAW_SERVICE_VERSION: "1.0.0" }, + description: "Custom", + }), + ).toBe("Custom"); + }); + + it("resolves version from explicit environment map", () => { + expect( + resolveGatewayServiceDescription({ + env: { OPENCLAW_PROFILE: "work", OPENCLAW_SERVICE_VERSION: "local" }, + environment: { OPENCLAW_SERVICE_VERSION: "remote" }, + }), + ).toBe("OpenClaw Gateway (profile: work, vremote)"); + }); +}); diff --git a/src/daemon/constants.ts b/src/daemon/constants.ts index 212eb93a2..3ee523b15 100644 --- a/src/daemon/constants.ts +++ b/src/daemon/constants.ts @@ -75,6 +75,20 @@ export function formatGatewayServiceDescription(params?: { return `OpenClaw Gateway (${parts.join(", ")})`; } +export function resolveGatewayServiceDescription(params: { + env: Record; + environment?: Record; + description?: string; +}): string { + return ( + params.description ?? + formatGatewayServiceDescription({ + profile: params.env.OPENCLAW_PROFILE, + version: params.environment?.OPENCLAW_SERVICE_VERSION ?? params.env.OPENCLAW_SERVICE_VERSION, + }) + ); +} + export function resolveNodeLaunchAgentLabel(): string { return NODE_LAUNCH_AGENT_LABEL; } diff --git a/src/daemon/launchd.ts b/src/daemon/launchd.ts index 3d33af682..795fe8280 100644 --- a/src/daemon/launchd.ts +++ b/src/daemon/launchd.ts @@ -2,8 +2,8 @@ import fs from "node:fs/promises"; import path from "node:path"; import type { GatewayServiceRuntime } from "./service-runtime.js"; import { - formatGatewayServiceDescription, GATEWAY_LAUNCH_AGENT_LABEL, + resolveGatewayServiceDescription, resolveGatewayLaunchAgentLabel, resolveLegacyGatewayLaunchAgentLabels, } from "./constants.js"; @@ -384,12 +384,7 @@ export async function installLaunchAgent({ const plistPath = resolveLaunchAgentPlistPathForLabel(env, label); await fs.mkdir(path.dirname(plistPath), { recursive: true }); - const serviceDescription = - description ?? - formatGatewayServiceDescription({ - profile: env.OPENCLAW_PROFILE, - version: environment?.OPENCLAW_SERVICE_VERSION ?? env.OPENCLAW_SERVICE_VERSION, - }); + const serviceDescription = resolveGatewayServiceDescription({ env, environment, description }); const plist = buildLaunchAgentPlist({ label, comment: serviceDescription, diff --git a/src/daemon/schtasks.ts b/src/daemon/schtasks.ts index d29d470ff..a70f10079 100644 --- a/src/daemon/schtasks.ts +++ b/src/daemon/schtasks.ts @@ -2,7 +2,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import type { GatewayServiceRuntime } from "./service-runtime.js"; import { splitArgsPreservingQuotes } from "./arg-split.js"; -import { formatGatewayServiceDescription, resolveGatewayWindowsTaskName } from "./constants.js"; +import { resolveGatewayServiceDescription, resolveGatewayWindowsTaskName } from "./constants.js"; import { formatLine } from "./output.js"; import { resolveGatewayStateDir } from "./paths.js"; import { parseKeyValueOutput } from "./runtime-parse.js"; @@ -190,12 +190,7 @@ export async function installScheduledTask({ await assertSchtasksAvailable(); const scriptPath = resolveTaskScriptPath(env); await fs.mkdir(path.dirname(scriptPath), { recursive: true }); - const taskDescription = - description ?? - formatGatewayServiceDescription({ - profile: env.OPENCLAW_PROFILE, - version: environment?.OPENCLAW_SERVICE_VERSION ?? env.OPENCLAW_SERVICE_VERSION, - }); + const taskDescription = resolveGatewayServiceDescription({ env, environment, description }); const script = buildTaskScript({ description: taskDescription, programArguments, diff --git a/src/daemon/systemd.ts b/src/daemon/systemd.ts index 6ef8af576..efe6f2591 100644 --- a/src/daemon/systemd.ts +++ b/src/daemon/systemd.ts @@ -4,6 +4,7 @@ import type { GatewayServiceRuntime } from "./service-runtime.js"; import { formatGatewayServiceDescription, LEGACY_GATEWAY_SYSTEMD_SERVICE_NAMES, + resolveGatewayServiceDescription, resolveGatewaySystemdServiceName, } from "./constants.js"; import { execFileUtf8 } from "./exec-file.js"; @@ -200,12 +201,7 @@ export async function installSystemdService({ const unitPath = resolveSystemdUnitPath(env); await fs.mkdir(path.dirname(unitPath), { recursive: true }); - const serviceDescription = - description ?? - formatGatewayServiceDescription({ - profile: env.OPENCLAW_PROFILE, - version: environment?.OPENCLAW_SERVICE_VERSION ?? env.OPENCLAW_SERVICE_VERSION, - }); + const serviceDescription = resolveGatewayServiceDescription({ env, environment, description }); const unit = buildSystemdUnit({ description: serviceDescription, programArguments,