mirror of https://github.com/openclaw/openclaw.git
fix(cli): honor update restart overrides
This commit is contained in:
parent
dff8692613
commit
366da7569a
|
|
@ -64,6 +64,7 @@ Docs: https://docs.openclaw.ai
|
|||
- CLI/Doctor: ensure `openclaw doctor --fix --non-interactive --yes` exits promptly after completion so one-shot automation no longer hangs. (#18502)
|
||||
- CLI/Doctor: auto-repair `dmPolicy="open"` configs missing wildcard allowlists and write channel-correct repair paths (including `channels.googlechat.dm.allowFrom`) so `openclaw doctor --fix` no longer leaves Google Chat configs invalid after attempted repair. (#18544)
|
||||
- CLI/Doctor: detect gateway service token drift when the gateway token is only provided via environment variables, keeping service repairs aligned after token rotation.
|
||||
- CLI/Update: run a standalone restart helper after updates, honoring service-name overrides and reporting restart initiation separately from confirmed restarts. (#18050)
|
||||
- CLI/Daemon: warn when a gateway restart sees a stale service token so users can reinstall with `openclaw gateway install --force`, and skip drift warnings for non-gateway service restarts. (#18018)
|
||||
- CLI/Status: fix `openclaw status --all` token summaries for bot-token-only channels so Mattermost/Zalo no longer show a bot+app warning. (#18527) Thanks @echo931.
|
||||
- CLI/Configure: make the `/model picker` allowlist prompt searchable with tokenized matching in `openclaw configure` so users can filter huge model lists by typing terms like `gpt-5.2 openai/`. (#19010) Thanks @bjesuiter.
|
||||
|
|
|
|||
|
|
@ -41,6 +41,22 @@ describe("restart-helper", () => {
|
|||
}
|
||||
});
|
||||
|
||||
it("uses OPENCLAW_SYSTEMD_UNIT override for systemd scripts", async () => {
|
||||
Object.defineProperty(process, "platform", { value: "linux" });
|
||||
const scriptPath = await prepareRestartScript({
|
||||
OPENCLAW_PROFILE: "default",
|
||||
OPENCLAW_SYSTEMD_UNIT: "custom-gateway",
|
||||
});
|
||||
|
||||
expect(scriptPath).toBeTruthy();
|
||||
const content = await fs.readFile(scriptPath!, "utf-8");
|
||||
expect(content).toContain("systemctl --user restart 'custom-gateway.service'");
|
||||
|
||||
if (scriptPath) {
|
||||
await fs.unlink(scriptPath);
|
||||
}
|
||||
});
|
||||
|
||||
it("creates a launchd restart script on macOS", async () => {
|
||||
Object.defineProperty(process, "platform", { value: "darwin" });
|
||||
process.getuid = () => 501;
|
||||
|
|
@ -62,6 +78,24 @@ describe("restart-helper", () => {
|
|||
}
|
||||
});
|
||||
|
||||
it("uses OPENCLAW_LAUNCHD_LABEL override on macOS", async () => {
|
||||
Object.defineProperty(process, "platform", { value: "darwin" });
|
||||
process.getuid = () => 501;
|
||||
|
||||
const scriptPath = await prepareRestartScript({
|
||||
OPENCLAW_PROFILE: "default",
|
||||
OPENCLAW_LAUNCHD_LABEL: "com.custom.openclaw",
|
||||
});
|
||||
|
||||
expect(scriptPath).toBeTruthy();
|
||||
const content = await fs.readFile(scriptPath!, "utf-8");
|
||||
expect(content).toContain("launchctl kickstart -k 'gui/501/com.custom.openclaw'");
|
||||
|
||||
if (scriptPath) {
|
||||
await fs.unlink(scriptPath);
|
||||
}
|
||||
});
|
||||
|
||||
it("creates a schtasks restart script on Windows", async () => {
|
||||
Object.defineProperty(process, "platform", { value: "win32" });
|
||||
|
||||
|
|
@ -84,6 +118,24 @@ describe("restart-helper", () => {
|
|||
}
|
||||
});
|
||||
|
||||
it("uses OPENCLAW_WINDOWS_TASK_NAME override on Windows", async () => {
|
||||
Object.defineProperty(process, "platform", { value: "win32" });
|
||||
|
||||
const scriptPath = await prepareRestartScript({
|
||||
OPENCLAW_PROFILE: "default",
|
||||
OPENCLAW_WINDOWS_TASK_NAME: "OpenClaw Gateway (custom)",
|
||||
});
|
||||
|
||||
expect(scriptPath).toBeTruthy();
|
||||
const content = await fs.readFile(scriptPath!, "utf-8");
|
||||
expect(content).toContain('schtasks /End /TN "OpenClaw Gateway (custom)"');
|
||||
expect(content).toContain('schtasks /Run /TN "OpenClaw Gateway (custom)"');
|
||||
|
||||
if (scriptPath) {
|
||||
await fs.unlink(scriptPath);
|
||||
}
|
||||
});
|
||||
|
||||
it("uses custom profile in service names", async () => {
|
||||
Object.defineProperty(process, "platform", { value: "linux" });
|
||||
const scriptPath = await prepareRestartScript({
|
||||
|
|
|
|||
|
|
@ -23,6 +23,30 @@ function isBatchSafe(value: string): boolean {
|
|||
return /^[A-Za-z0-9 _\-().]+$/.test(value);
|
||||
}
|
||||
|
||||
function resolveSystemdUnit(env: NodeJS.ProcessEnv): string {
|
||||
const override = env.OPENCLAW_SYSTEMD_UNIT?.trim();
|
||||
if (override) {
|
||||
return override.endsWith(".service") ? override : `${override}.service`;
|
||||
}
|
||||
return `${resolveGatewaySystemdServiceName(env.OPENCLAW_PROFILE)}.service`;
|
||||
}
|
||||
|
||||
function resolveLaunchdLabel(env: NodeJS.ProcessEnv): string {
|
||||
const override = env.OPENCLAW_LAUNCHD_LABEL?.trim();
|
||||
if (override) {
|
||||
return override;
|
||||
}
|
||||
return resolveGatewayLaunchAgentLabel(env.OPENCLAW_PROFILE);
|
||||
}
|
||||
|
||||
function resolveWindowsTaskName(env: NodeJS.ProcessEnv): string {
|
||||
const override = env.OPENCLAW_WINDOWS_TASK_NAME?.trim();
|
||||
if (override) {
|
||||
return override;
|
||||
}
|
||||
return resolveGatewayWindowsTaskName(env.OPENCLAW_PROFILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a standalone script to restart the gateway service.
|
||||
* This script is written to a temporary directory and does not depend on
|
||||
|
|
@ -41,8 +65,8 @@ export async function prepareRestartScript(
|
|||
|
||||
try {
|
||||
if (platform === "linux") {
|
||||
const serviceName = resolveGatewaySystemdServiceName(env.OPENCLAW_PROFILE);
|
||||
const escaped = shellEscape(`${serviceName}.service`);
|
||||
const unitName = resolveSystemdUnit(env);
|
||||
const escaped = shellEscape(unitName);
|
||||
filename = `openclaw-restart-${timestamp}.sh`;
|
||||
scriptContent = `#!/bin/sh
|
||||
# Standalone restart script — survives parent process termination.
|
||||
|
|
@ -53,7 +77,7 @@ systemctl --user restart '${escaped}'
|
|||
rm -f "$0"
|
||||
`;
|
||||
} else if (platform === "darwin") {
|
||||
const label = resolveGatewayLaunchAgentLabel(env.OPENCLAW_PROFILE);
|
||||
const label = resolveLaunchdLabel(env);
|
||||
const escaped = shellEscape(label);
|
||||
// Fallback to 501 if getuid is not available (though it should be on macOS)
|
||||
const uid = process.getuid ? process.getuid() : 501;
|
||||
|
|
@ -67,7 +91,7 @@ launchctl kickstart -k 'gui/${uid}/${escaped}'
|
|||
rm -f "$0"
|
||||
`;
|
||||
} else if (platform === "win32") {
|
||||
const taskName = resolveGatewayWindowsTaskName(env.OPENCLAW_PROFILE);
|
||||
const taskName = resolveWindowsTaskName(env);
|
||||
if (!isBatchSafe(taskName)) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -400,9 +400,10 @@ async function maybeRestartService(params: {
|
|||
|
||||
try {
|
||||
let restarted = false;
|
||||
let restartInitiated = false;
|
||||
if (params.restartScriptPath) {
|
||||
await runRestartScript(params.restartScriptPath);
|
||||
restarted = true;
|
||||
restartInitiated = true;
|
||||
} else {
|
||||
restarted = await runDaemonRestart();
|
||||
}
|
||||
|
|
@ -423,6 +424,16 @@ async function maybeRestartService(params: {
|
|||
delete process.env.OPENCLAW_UPDATE_IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (!params.opts.json && restartInitiated) {
|
||||
defaultRuntime.log(theme.success("Daemon restart initiated."));
|
||||
defaultRuntime.log(
|
||||
theme.muted(
|
||||
`Verify with \`${replaceCliName(formatCliCommand("openclaw gateway status"), CLI_NAME)}\` once the gateway is back.`,
|
||||
),
|
||||
);
|
||||
defaultRuntime.log("");
|
||||
}
|
||||
} catch (err) {
|
||||
if (!params.opts.json) {
|
||||
defaultRuntime.log(theme.warn(`Daemon restart failed: ${String(err)}`));
|
||||
|
|
|
|||
Loading…
Reference in New Issue