
















@@ -2,6 +2,7 @@ import { spawn } from "node:child_process";
22import os from "node:os";
33import path from "node:path";
44import { formatErrorMessage } from "../infra/errors.js";
5+import { sanitizeHostExecEnv } from "../infra/host-env-security.js";
56import { normalizeOptionalString } from "../shared/string-coerce.js";
67import { sanitizeForLog } from "../terminal/ansi.js";
78import { resolveGatewayLaunchAgentLabel } from "./constants.js";
@@ -25,6 +26,13 @@ export type LaunchdRestartTarget = {
2526const START_AFTER_EXIT_PRINT_RETRY_COUNT = 15;
2627const START_AFTER_EXIT_PRINT_RETRY_DELAY_SECONDS = 0.2;
272829+type LaunchdRestartLogEnv = {
30+HOME?: string;
31+USERPROFILE?: string;
32+OPENCLAW_STATE_DIR?: string;
33+OPENCLAW_PROFILE?: string;
34+};
35+2836function assertValidLaunchAgentLabel(label: string): string {
2937const trimmed = label.trim();
3038if (!/^[A-Za-z0-9._-]+$/.test(trimmed)) {
@@ -40,6 +48,27 @@ function resolveGuiDomain(): string {
4048return `gui/${process.getuid()}`;
4149}
425051+function collectStringEnvOverrides(
52+env?: Record<string, string | undefined>,
53+): Record<string, string> | undefined {
54+const overrides = Object.fromEntries(
55+Object.entries(env ?? {}).filter(
56+(entry): entry is [string, string] => typeof entry[1] === "string",
57+),
58+);
59+return Object.keys(overrides).length > 0 ? overrides : undefined;
60+}
61+62+function collectRestartLogEnv(env?: Record<string, string | undefined>): LaunchdRestartLogEnv {
63+const source = { ...process.env, ...env };
64+return {
65+HOME: source.HOME,
66+USERPROFILE: source.USERPROFILE,
67+OPENCLAW_STATE_DIR: source.OPENCLAW_STATE_DIR,
68+OPENCLAW_PROFILE: source.OPENCLAW_PROFILE,
69+};
70+}
71+4372function resolveLaunchAgentLabel(env?: Record<string, string | undefined>): string {
4473const envLabel = normalizeOptionalString(env?.OPENCLAW_LAUNCHD_LABEL);
4574if (envLabel) {
@@ -80,11 +109,11 @@ export function isCurrentProcessLaunchdServiceLabel(
8010981110function buildLaunchdRestartScript(
82111mode: LaunchdRestartHandoffMode,
83-env: Record<string, string | undefined>,
112+restartLogEnv: LaunchdRestartLogEnv,
84113): string {
85114const waitForCallerPid = `wait_pid="$4"
86115label="$5"
87-${renderPosixRestartLogSetup(env)}
116+${renderPosixRestartLogSetup(restartLogEnv)}
88117printf '[%s] openclaw restart attempt source=launchd-handoff mode=${mode} target=%s waitPid=%s\\n' "$(date -u +%FT%TZ)" "$service_target" "$wait_pid" >&2
89118if [ -n "$wait_pid" ] && [ "$wait_pid" -gt 1 ] 2>/dev/null; then
90119 while kill -0 "$wait_pid" >/dev/null 2>&1; do
@@ -169,13 +198,17 @@ export function scheduleDetachedLaunchdRestartHandoff(params: {
169198typeof params.waitForPid === "number" && Number.isFinite(params.waitForPid)
170199 ? Math.floor(params.waitForPid)
171200 : 0;
172-const restartEnv = { ...process.env, ...params.env };
201+const restartLogEnv = collectRestartLogEnv(params.env);
202+const restartEnv = sanitizeHostExecEnv({
203+baseEnv: process.env,
204+overrides: collectStringEnvOverrides(params.env),
205+});
173206try {
174207const child = spawn(
175208"/bin/sh",
176209[
177210"-c",
178-buildLaunchdRestartScript(params.mode, restartEnv),
211+buildLaunchdRestartScript(params.mode, restartLogEnv),
179212"openclaw-launchd-restart-handoff",
180213target.serviceTarget,
181214target.domain,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。