

















@@ -7,7 +7,7 @@ import { collectDurableServiceEnvVarSources } from "../config/state-dir-dotenv.j
77import type { OpenClawConfig } from "../config/types.js";
88import { resolveSecretInputRef } from "../config/types.secrets.js";
99import { resolveGatewayLaunchAgentLabel } from "../daemon/constants.js";
10-import { resolveGatewayStateDir } from "../daemon/paths.js";
10+import { resolveGatewayStateDir, resolveGatewayTaskScriptPath } from "../daemon/paths.js";
1111import {
1212OPENCLAW_WRAPPER_ENV_KEY,
1313resolveGatewayProgramArguments,
@@ -519,12 +519,24 @@ export async function buildGatewayInstallPlan(params: {
519519devMode: params.devMode,
520520nodePath: params.nodePath,
521521});
522-const wrapperPath = await resolveOpenClawWrapperPath(
523-params.wrapperPath ?? params.env[OPENCLAW_WRAPPER_ENV_KEY],
524-);
522+const wrapperInput = params.wrapperPath ?? params.env[OPENCLAW_WRAPPER_ENV_KEY];
523+const wrapperPointsAtWindowsTaskScript =
524+Boolean(wrapperInput?.trim()) &&
525+platform === "win32" &&
526+isSameServicePath(wrapperInput, resolveGatewayTaskScriptPath(params.env), platform);
527+if (wrapperPointsAtWindowsTaskScript) {
528+params.warn?.(
529+`Ignoring ${OPENCLAW_WRAPPER_ENV_KEY} because it points to the Windows task script; using the OpenClaw gateway entrypoint directly to avoid a recursive gateway.cmd wrapper.`,
530+);
531+}
532+const wrapperPath = wrapperPointsAtWindowsTaskScript
533+ ? undefined
534+ : await resolveOpenClawWrapperPath(wrapperInput);
525535const serviceInputEnv: Record<string, string | undefined> = wrapperPath
526536 ? { ...params.env, [OPENCLAW_WRAPPER_ENV_KEY]: wrapperPath }
527- : params.env;
537+ : wrapperPointsAtWindowsTaskScript
538+ ? omitEnvKey(params.env, OPENCLAW_WRAPPER_ENV_KEY)
539+ : params.env;
528540const { programArguments, workingDirectory } = await resolveGatewayProgramArguments({
529541port: params.port,
530542dev: devMode,
@@ -578,6 +590,36 @@ export async function buildGatewayInstallPlan(params: {
578590};
579591}
580592593+function normalizeServicePathForCompare(
594+value: string | undefined,
595+platform: NodeJS.Platform,
596+): string | undefined {
597+const trimmed = value?.trim();
598+if (!trimmed) {
599+return undefined;
600+}
601+return platform === "win32" ? path.win32.resolve(trimmed).toLowerCase() : path.resolve(trimmed);
602+}
603+604+function isSameServicePath(
605+left: string | undefined,
606+right: string | undefined,
607+platform: NodeJS.Platform,
608+): boolean {
609+const normalizedLeft = normalizeServicePathForCompare(left, platform);
610+const normalizedRight = normalizeServicePathForCompare(right, platform);
611+return Boolean(normalizedLeft && normalizedRight && normalizedLeft === normalizedRight);
612+}
613+614+function omitEnvKey(
615+env: Record<string, string | undefined>,
616+key: string,
617+): Record<string, string | undefined> {
618+const next = { ...env };
619+delete next[key];
620+return next;
621+}
622+581623export function gatewayInstallErrorHint(platform = process.platform): string {
582624return platform === "win32"
583625 ? "Tip: native Windows now falls back to a per-user Startup-folder login item when Scheduled Task creation is denied; if install still fails, rerun from an elevated PowerShell or skip service install."
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。