






















@@ -10,6 +10,7 @@ import { resolveFutureConfigActionBlock } from "../../config/future-version-guar
1010import { readConfigFileSnapshotForWrite } from "../../config/io.js";
1111import { resolveGatewayPort } from "../../config/paths.js";
1212import type { OpenClawConfig } from "../../config/types.js";
13+import { OPENCLAW_WRAPPER_ENV_KEY, resolveOpenClawWrapperPath } from "../../daemon/program-args.js";
1314import { readEmbeddedGatewayToken } from "../../daemon/service-audit.js";
1415import { resolveGatewayService } from "../../daemon/service.js";
1516import type { GatewayServiceCommandConfig } from "../../daemon/service.js";
@@ -44,6 +45,13 @@ function mergeInstallInvocationEnv(params: {
4445continue;
4546}
4647const upper = key.toUpperCase();
48+if (upper === OPENCLAW_WRAPPER_ENV_KEY) {
49+const value = rawValue.trim();
50+if (value) {
51+preservedServiceEnv[OPENCLAW_WRAPPER_ENV_KEY] = value;
52+}
53+continue;
54+}
4755if (
4856upper === "HOME" ||
4957upper === "PATH" ||
@@ -99,6 +107,19 @@ export async function runDaemonInstall(opts: DaemonInstallOptions) {
99107fail('Invalid --runtime (use "node" or "bun")');
100108return;
101109}
110+let wrapperPath: string | undefined;
111+if (opts.wrapper !== undefined) {
112+try {
113+wrapperPath = await resolveOpenClawWrapperPath(opts.wrapper);
114+if (!wrapperPath) {
115+fail("Invalid --wrapper");
116+return;
117+}
118+} catch (err) {
119+fail(`Invalid --wrapper: ${String(err)}`);
120+return;
121+}
122+}
102123103124const service = resolveGatewayService();
104125let loaded = false;
@@ -122,6 +143,14 @@ export async function runDaemonInstall(opts: DaemonInstallOptions) {
122143env: process.env,
123144 existingServiceEnv,
124145});
146+if (!wrapperPath) {
147+try {
148+wrapperPath = await resolveOpenClawWrapperPath(installEnv[OPENCLAW_WRAPPER_ENV_KEY]);
149+} catch (err) {
150+fail(`Invalid ${OPENCLAW_WRAPPER_ENV_KEY}: ${String(err)}`);
151+return;
152+}
153+}
125154if (loaded) {
126155if (!opts.force) {
127156const autoRefreshMessage = await getGatewayServiceAutoRefreshMessage({
@@ -130,6 +159,7 @@ export async function runDaemonInstall(opts: DaemonInstallOptions) {
130159 installEnv,
131160 port,
132161runtime: runtimeRaw,
162+ wrapperPath,
133163existingEnvironment: existingServiceEnv,
134164config: cfg,
135165});
@@ -182,6 +212,7 @@ export async function runDaemonInstall(opts: DaemonInstallOptions) {
182212env: installEnv,
183213 port,
184214runtime: runtimeRaw,
215+ wrapperPath,
185216existingEnvironment: existingServiceEnv,
186217warn: (message) => {
187218if (json) {
@@ -217,6 +248,7 @@ async function getGatewayServiceAutoRefreshMessage(params: {
217248installEnv: NodeJS.ProcessEnv;
218249port: number;
219250runtime: GatewayDaemonRuntime;
251+wrapperPath?: string;
220252existingEnvironment?: Record<string, string | undefined>;
221253config: OpenClawConfig;
222254}): Promise<string | undefined> {
@@ -231,6 +263,7 @@ async function getGatewayServiceAutoRefreshMessage(params: {
231263env: params.installEnv,
232264port: params.port,
233265runtime: params.runtime,
266+wrapperPath: params.wrapperPath,
234267existingEnvironment: params.existingEnvironment,
235268warn: () => undefined,
236269config: params.config,
@@ -242,6 +275,26 @@ async function getGatewayServiceAutoRefreshMessage(params: {
242275return "Gateway service OPENCLAW_GATEWAY_TOKEN differs from the current install plan; refreshing the install.";
243276}
244277}
278+const wrapperRequested = Boolean(
279+params.wrapperPath || normalizeOptionalString(params.installEnv[OPENCLAW_WRAPPER_ENV_KEY]),
280+);
281+if (wrapperRequested) {
282+const plannedInstall = await buildGatewayInstallPlan({
283+env: params.installEnv,
284+port: params.port,
285+runtime: params.runtime,
286+wrapperPath: params.wrapperPath,
287+existingEnvironment: params.existingEnvironment,
288+warn: () => undefined,
289+config: params.config,
290+});
291+if (
292+plannedInstall.programArguments.join("\u0000") !==
293+currentCommand.programArguments.join("\u0000")
294+) {
295+return "Gateway service command differs from the current wrapper install plan; refreshing the install.";
296+}
297+}
245298const currentExecPath = currentCommand.programArguments[0]?.trim();
246299if (!currentExecPath) {
247300return undefined;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。