UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

177 lines (176 loc) • 6.01 kB
import { l as normalizeOptionalString } from "./string-coerce-1VuiLaaR.mjs"; import { t as mergeProcessEnv } from "./process-env-DlZFJzq6.mjs"; import { t as formatErrorMessage } from "./errors-O33D01XW.mjs"; import { r as renderPosixRestartLogSetup } from "./restart-logs-6OI2aKFf.mjs"; import { t as resolveServiceManagerEnv } from "./service-process-env-C6isS50W.mjs"; import { n as resolveLaunchAgentLabel } from "./launchd-label-CDVrpZuO.mjs"; import { n as ok, t as err } from "./result-BQGgYouL.mjs"; import { _ as renderSystemLaunchDaemonOwnershipShellProbe } from "./launchd-service-files-UOyeu4f-.mjs"; import "./launchd-plist-CCfoVvU9.mjs"; import { g as resolveLaunchAgentGuiDomain } from "./launchd-runtime-CkSyqekH.mjs"; import path from "node:path"; import os from "node:os"; import { spawn } from "node:child_process"; //#region src/daemon/launchd-restart-handoff.ts /** Detached macOS launchd restart handoff for restarting from inside the service. */ const RELOAD_BOOTOUT_WAIT_DELAY_SECONDS = 1; const RELOAD_BOOTOUT_WAIT_COUNT = 35; const RELOAD_BOOTSTRAP_RETRY_COUNT = 15; function resolveLaunchdRestartTarget(env = process.env) { const domain = resolveLaunchAgentGuiDomain(); const label = resolveLaunchAgentLabel(env); const home = normalizeOptionalString(env.HOME) || os.homedir(); return { domain, label, plistPath: path.join(home, "Library", "LaunchAgents", `${label}.plist`), serviceTarget: `${domain}/${label}` }; } function buildLaunchdRestartScript(mode, restartLogEnv, label) { const preamble = `service_target="$1" domain="$2" plist_path="$3" wait_pid="$4" ${renderPosixRestartLogSetup(restartLogEnv)} printf '[%s] openclaw restart attempt source=handoff mode=${mode} target=%s pid=%s interactive=0\\n' "$(date -u +%FT%TZ)" "$service_target" "$wait_pid" >&2 if [ -n "$wait_pid" ] && [ "$wait_pid" -gt 1 ] 2>/dev/null; then while kill -0 "$wait_pid" >/dev/null 2>&1; do sleep 0.1 done fi `; const systemOwnershipGuard = `${renderSystemLaunchDaemonOwnershipShellProbe(label)} if [ -n "$openclaw_system_launchd_conflict" ]; then printf '[%s] openclaw restart blocked source=handoff mode=${mode} reason=%s interactive=0\n' "$(date -u +%FT%TZ)" "$openclaw_system_launchd_detail" >&2 exit 78 fi `; if (mode === "park") return `${preamble} status=0 if launchctl bootout "$service_target"; then status=0 else status=$? fi if [ "$status" -eq 0 ]; then printf '[%s] openclaw service park done source=handoff interactive=0\\n' "$(date -u +%FT%TZ)" >&2 else printf '[%s] openclaw service park failed source=handoff status=%s interactive=0\\n' "$(date -u +%FT%TZ)" "$status" >&2 fi exit "$status" `; const completion = `if [ "$status" -eq 0 ]; then printf '[%s] openclaw restart done source=handoff mode=${mode} interactive=0\\n' "$(date -u +%FT%TZ)" >&2 else printf '[%s] openclaw restart failed source=handoff mode=${mode} status=%s interactive=0\\n' "$(date -u +%FT%TZ)" "$status" >&2 fi exit "$status" `; if (mode === "reload") return `${preamble} ${systemOwnershipGuard} status=0 launchctl enable "$service_target" launchctl bootout "$service_target" >/dev/null 2>&1 || true ${`bootout_wait_count="${RELOAD_BOOTOUT_WAIT_COUNT}" while [ "$bootout_wait_count" -gt 0 ]; do if ! launchctl print "$service_target" >/dev/null 2>&1; then break fi bootout_wait_count=$((bootout_wait_count - 1)) sleep ${RELOAD_BOOTOUT_WAIT_DELAY_SECONDS} done `} ${`bootstrap_retry_count="${RELOAD_BOOTSTRAP_RETRY_COUNT}" while :; do if launchctl bootstrap "$domain" "$plist_path"; then status=0 break else # Capture inside the else: after a completed if with a false condition, # $? is 0, which would let exhausted retries report a successful restart. status=$? fi if launchctl print "$service_target" >/dev/null 2>&1; then if launchctl kickstart -k "$service_target"; then status=0 break else # The pending bootout can finish between print and kickstart. Keep # retrying bootstrap if that check-then-act race deregisters the label. status=$? fi fi bootstrap_retry_count=$((bootstrap_retry_count - 1)) if [ "$bootstrap_retry_count" -le 0 ]; then break fi sleep ${RELOAD_BOOTOUT_WAIT_DELAY_SECONDS} done `} ${completion}`; const kickstart = mode === "kickstart" ? "kickstart -k" : "kickstart"; return `${preamble} ${systemOwnershipGuard} status=0 launchctl enable "$service_target" if launchctl ${kickstart} "$service_target"; then status=0 else status=$? if launchctl bootstrap "$domain" "$plist_path"; then status=0 else launchctl ${kickstart} "$service_target" status=$? fi fi ${completion}`; } function scheduleDetachedLaunchdHandoff(params) { const target = resolveLaunchdRestartTarget(params.env); const waitForPid = typeof params.waitForPid === "number" && Number.isFinite(params.waitForPid) ? Math.floor(params.waitForPid) : 0; const restartLogEnv = { ...process.env, ...params.env }; const restartEnv = resolveServiceManagerEnv(mergeProcessEnv([ process.env, params.env, { PATH: process.env.PATH } ])); try { const child = spawn("/bin/sh", [ "-c", buildLaunchdRestartScript(params.mode, restartLogEnv, target.label), "openclaw-launchd-restart-handoff", target.serviceTarget, target.domain, target.plistPath, String(waitForPid) ], { detached: true, stdio: "ignore", env: restartEnv }); const spawned = new Promise((resolve) => { child.once("spawn", () => resolve(true)); child.once("error", () => resolve(false)); }); child.unref(); return ok(spawned); } catch (error) { return err(formatErrorMessage(error)); } } function scheduleDetachedLaunchdRestartHandoff(params) { return scheduleDetachedLaunchdHandoff(params); } function scheduleDetachedLaunchdMaintenancePark(params) { return scheduleDetachedLaunchdHandoff({ ...params, mode: "park" }); } //#endregion export { scheduleDetachedLaunchdRestartHandoff as n, scheduleDetachedLaunchdMaintenancePark as t };