From 4ebefe647a7c1800a27acf8359734504de724fbe Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Thu, 26 Feb 2026 02:52:00 -0500 Subject: [PATCH] fix(daemon): keep launchd KeepAlive while preserving restart hardening --- CHANGELOG.md | 2 +- src/daemon/launchd-plist.ts | 4 +--- src/daemon/launchd.test.ts | 9 ++++----- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21e75f9ab6d..90f019acc78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ Docs: https://docs.openclaw.ai ### Fixes -- Daemon/macOS launchd: forward proxy env vars into supervised service environments, switch LaunchAgent keepalive policy to crash-only with throttling, and harden restart sequencing to `print -> bootout -> wait old pid exit -> bootstrap -> kickstart`. (#27276) thanks @frankekn. +- Daemon/macOS launchd: forward proxy env vars into supervised service environments, keep LaunchAgent `KeepAlive=true` semantics, and harden restart sequencing to `print -> bootout -> wait old pid exit -> bootstrap -> kickstart`. (#27276) thanks @frankekn. - Android/Node invoke: remove native gateway WebSocket `Origin` header to avoid false origin rejections, unify invoke command registry/policy/error parsing paths, and keep command availability checks centralized to reduce dispatcher/advertisement drift. (#27257) Thanks @obviyus. - CI/Windows: shard the Windows `checks-windows` test lane into two matrix jobs and honor explicit shard index overrides in `scripts/test-parallel.mjs` to reduce CI critical-path wall time. (#27234) Thanks @joshavant. diff --git a/src/daemon/launchd-plist.ts b/src/daemon/launchd-plist.ts index 7918e1c8a37..e685cd9941c 100644 --- a/src/daemon/launchd-plist.ts +++ b/src/daemon/launchd-plist.ts @@ -1,7 +1,5 @@ import fs from "node:fs/promises"; -const LAUNCHD_THROTTLE_INTERVAL_SECONDS = 5; - const plistEscape = (value: string): string => value .replaceAll("&", "&") @@ -108,5 +106,5 @@ export function buildLaunchAgentPlist({ ? `\n Comment\n ${plistEscape(comment.trim())}` : ""; const envXml = renderEnvDict(environment); - return `\n\n\n \n Label\n ${plistEscape(label)}\n ${commentXml}\n RunAtLoad\n \n KeepAlive\n \n SuccessfulExit\n \n \n ThrottleInterval\n ${LAUNCHD_THROTTLE_INTERVAL_SECONDS}\n ProgramArguments\n ${argsXml}\n \n ${workingDirXml}\n StandardOutPath\n ${plistEscape(stdoutPath)}\n StandardErrorPath\n ${plistEscape(stderrPath)}${envXml}\n \n\n`; + return `\n\n\n \n Label\n ${plistEscape(label)}\n ${commentXml}\n RunAtLoad\n \n KeepAlive\n \n ProgramArguments\n ${argsXml}\n \n ${workingDirXml}\n StandardOutPath\n ${plistEscape(stdoutPath)}\n StandardErrorPath\n ${plistEscape(stderrPath)}${envXml}\n \n\n`; } diff --git a/src/daemon/launchd.test.ts b/src/daemon/launchd.test.ts index 7465666a158..ac092536c5a 100644 --- a/src/daemon/launchd.test.ts +++ b/src/daemon/launchd.test.ts @@ -185,7 +185,7 @@ describe("launchd install", () => { expect(plist).toContain(`${tmpDir}`); }); - it("writes crash-only KeepAlive policy with throttle interval", async () => { + it("writes KeepAlive=true policy", async () => { const env = createDefaultLaunchdEnv(); await installLaunchAgent({ env, @@ -196,10 +196,9 @@ describe("launchd install", () => { const plistPath = resolveLaunchAgentPlistPath(env); const plist = state.files.get(plistPath) ?? ""; expect(plist).toContain("KeepAlive"); - expect(plist).toContain("SuccessfulExit"); - expect(plist).toContain(""); - expect(plist).toContain("ThrottleInterval"); - expect(plist).toContain("5"); + expect(plist).toContain(""); + expect(plist).not.toContain("SuccessfulExit"); + expect(plist).not.toContain("ThrottleInterval"); }); it("restarts LaunchAgent with bootout-bootstrap-kickstart order", async () => {