fix(daemon): recovery hints target the wrong profile or container (#130216)

* fix(daemon): preserve profile context in systemd recovery hints

* fix(cli): remove obsolete daemon container helper export
This commit is contained in:
Peter Steinberger
2026-08-26 12:55:48 -07:00
committed by GitHub
parent c3ea9775ca
commit 8585e7e04e
8 changed files with 38 additions and 28 deletions
-14
View File
@@ -6,7 +6,6 @@ import {
parsePortFromArgs,
renderRuntimeHints,
renderGatewayServiceStartHints,
resolveDaemonContainerContext,
resolveRuntimeStatusColor,
} from "./shared.js";
@@ -61,19 +60,6 @@ describe("renderGatewayServiceStartHints", () => {
).toContain("logged-in macOS GUI session");
});
it("resolves daemon container context from either env key", () => {
expect(
resolveDaemonContainerContext({
OPENCLAW_CONTAINER: "openclaw-demo-container",
} as NodeJS.ProcessEnv),
).toBe("openclaw-demo-container");
expect(
resolveDaemonContainerContext({
OPENCLAW_CONTAINER_HINT: "openclaw-demo-container",
} as NodeJS.ProcessEnv),
).toBe("openclaw-demo-container");
});
it("prepends a single container restart hint when OPENCLAW_CONTAINER is set", () => {
expect(
renderGatewayServiceStartHints({
-1
View File
@@ -19,7 +19,6 @@ import { createDaemonActionContext } from "./response.js";
export { formatRuntimeStatus };
export { parsePort };
export { resolveDaemonContainerContext };
/** Create install action context with JSON flag normalization. */
export function createDaemonInstallActionContext(jsonFlag: unknown) {
+1 -2
View File
@@ -107,7 +107,6 @@ vi.mock("./shared.js", () => ({
filterDaemonEnv: () => ({}),
formatRuntimeStatus: () => "running (pid 8000)",
resolveRuntimeStatusColor: () => "",
resolveDaemonContainerContext: () => null,
renderRuntimeHints: () => [],
safeDaemonEnv: () => [],
}));
@@ -475,7 +474,7 @@ describe("printDaemonStatus", () => {
expect(renderSystemdUnavailableHintsMock).toHaveBeenCalledWith({
wsl: true,
kind: "generic_unavailable",
container: false,
env: { WSL_DISTRO_NAME: "Ubuntu" },
});
expectMockLineContains(runtime.log, "Service: systemd (unknown)");
expect(runtime.log.mock.calls.flat().join("\n")).not.toContain("Service: systemd (not loaded)");
+1 -3
View File
@@ -29,7 +29,6 @@ import {
createCliStatusTextStyles,
filterDaemonEnv,
formatRuntimeStatus,
resolveDaemonContainerContext,
resolveRuntimeStatusColor,
renderRuntimeHints,
safeDaemonEnv,
@@ -407,12 +406,11 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean; d
isSystemdUnavailableDetail(systemdUnavailableDetail);
if (systemdUnavailable) {
const serviceEnv = service.command?.environment ?? process.env;
const container = Boolean(resolveDaemonContainerContext(serviceEnv));
defaultRuntime.error(errorText("systemd user services unavailable."));
for (const hint of renderSystemdUnavailableHints({
wsl: isWSLEnv(serviceEnv),
kind: classifySystemdUnavailableDetail(systemdUnavailableDetail),
container,
env: serviceEnv,
})) {
defaultRuntime.error(errorText(hint));
}
+28
View File
@@ -58,6 +58,34 @@ describe("buildGatewayRuntimeHints", () => {
expect(hints.join("\n")).not.toContain("systemd user services are unavailable");
});
it.each([
{
env: { OPENCLAW_PROFILE: "blue" },
command: "openclaw --profile blue gateway",
},
{
env: { OPENCLAW_CONTAINER_HINT: "sandbox" },
command: "openclaw --container sandbox gateway",
},
{
env: { OPENCLAW_PROFILE: "blue", OPENCLAW_CONTAINER_HINT: "sandbox" },
command: "openclaw --container sandbox gateway",
},
])("preserves the active target in systemd recovery commands: $command", ({ env, command }) => {
const hints = buildGatewayRuntimeHints(
{
status: "unknown",
detail: "systemctl --user unavailable: Failed to connect to bus",
},
{ platform: "linux", env },
);
expect(hints.some((hint) => hint.includes(command))).toBe(true);
expect(hints.some((hint) => hint.includes("headless server"))).toBe(
!env.OPENCLAW_CONTAINER_HINT,
);
});
it("guides recovery when systemd hit its restart start limit (crash loop)", () => {
// Real give-up shape: process kept failing (Result=exit-code) until NRestarts
// reached StartLimitBurst and systemd stopped restarting.
+1 -3
View File
@@ -5,7 +5,6 @@ import {
resolveGatewaySystemdServiceName,
resolveGatewayWindowsTaskName,
} from "../daemon/constants.js";
import { resolveDaemonContainerContext } from "../daemon/container-context.js";
import { formatRuntimeStatus } from "../daemon/runtime-format.js";
import { buildPlatformRuntimeLogHints } from "../daemon/runtime-hints.js";
import {
@@ -45,7 +44,6 @@ export function buildGatewayRuntimeHints(
}
const platform = options.platform ?? process.platform;
const env = options.env ?? process.env;
const container = Boolean(resolveDaemonContainerContext(env));
const fileLog = (() => {
try {
return getResolvedLoggerSettings().file;
@@ -58,7 +56,7 @@ export function buildGatewayRuntimeHints(
...renderSystemdUnavailableHints({
wsl: isWSLEnv(env),
kind: classifySystemdUnavailableDetail(runtime.detail),
container,
env,
}),
);
if (fileLog) {
+3 -2
View File
@@ -49,14 +49,15 @@ describe("renderSystemdUnavailableHints", () => {
});
it("skips headless recovery hints when container context is known", () => {
const env = { OPENCLAW_CONTAINER_HINT: "sandbox" };
expect(
renderSystemdUnavailableHints({
kind: "user_bus_unavailable",
container: true,
env,
}),
).toEqual([
"systemd user services are unavailable; install/enable systemd or run the gateway under your supervisor.",
`If you're in a container, run the gateway in the foreground instead of \`${formatCliCommand("openclaw gateway")}\`.`,
`If you're in a container, run the gateway in the foreground instead of \`${formatCliCommand("openclaw gateway", env)}\`.`,
]);
});
});
+4 -3
View File
@@ -1,5 +1,6 @@
/** Renders Linux systemd availability hints for gateway service commands. */
import { formatCliCommand } from "../cli/command-format.js";
import { resolveDaemonContainerContext } from "./container-context.js";
import {
classifySystemdUnavailableDetail,
type SystemdUnavailableKind,
@@ -8,7 +9,7 @@ import {
type SystemdUnavailableHintOptions = {
wsl?: boolean;
kind?: SystemdUnavailableKind | null;
container?: boolean;
env?: Record<string, string | undefined>;
};
/** Detects details that should get systemd availability repair hints. */
@@ -36,9 +37,9 @@ export function renderSystemdUnavailableHints(
}
return [
"systemd user services are unavailable; install/enable systemd or run the gateway under your supervisor.",
...(options.container || options.kind !== "user_bus_unavailable"
...(resolveDaemonContainerContext(options.env) || options.kind !== "user_bus_unavailable"
? []
: renderSystemdHeadlessServerHints()),
`If you're in a container, run the gateway in the foreground instead of \`${formatCliCommand("openclaw gateway")}\`.`,
`If you're in a container, run the gateway in the foreground instead of \`${formatCliCommand("openclaw gateway", options.env)}\`.`,
];
}