Skip to content

Commit a00c583

Browse files
authored
fix(cli): suppress systemd hints for live gateway (#85336)
* fix(cli): suppress systemd hints for live gateway * test(cli): type systemd hint mock
1 parent fc47c1f commit a00c583

3 files changed

Lines changed: 49 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Docs: https://docs.openclaw.ai
4141
- Agents/OpenAI: preserve structured provider error code, type, and redacted body metadata on boundary-aware transport failures.
4242
- Doctor/Codex: point native Codex asset warnings at the canonical `openclaw migrate plan codex` preview command. Fixes #84948. Thanks @markoa.
4343
- CLI/models: make `capability model auth logout --agent` remove auth profiles from the selected non-default agent store. Fixes #85092. Thanks @islandpreneur007.
44+
- CLI/status: suppress systemd user-service setup hints when `openclaw status --deep` can already reach a running Gateway RPC service. Fixes #85094. Thanks @islandpreneur007.
4445
- CLI/agents: retry transient normal-close Gateway handshakes before falling back to embedded `openclaw agent` execution.
4546
- CLI/update: keep managed Gateway service stop/restart status lines out of `openclaw update --json` stdout so package-update automation can parse the JSON payload.
4647
- Plugins: resolve OpenClaw plugin SDK subpaths for native external plugin runtimes without mutating package installs or broadening process-wide module resolution.

src/cli/daemon-cli/status.print.test.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ const runtime = vi.hoisted(() => ({
99
const resolveControlUiLinksMock = vi.hoisted(() =>
1010
vi.fn((_opts?: unknown) => ({ httpUrl: "http://127.0.0.1:18789" })),
1111
);
12+
const isSystemdUnavailableDetailMock = vi.hoisted(() => vi.fn(() => false));
13+
const renderSystemdUnavailableHintsMock = vi.hoisted(() => vi.fn<() => string[]>(() => []));
1214

1315
vi.mock("../../runtime.js", () => ({
1416
defaultRuntime: runtime,
@@ -46,8 +48,8 @@ vi.mock("../../daemon/restart-logs.js", () => ({
4648
}));
4749

4850
vi.mock("../../daemon/systemd-hints.js", () => ({
49-
isSystemdUnavailableDetail: () => false,
50-
renderSystemdUnavailableHints: () => [],
51+
isSystemdUnavailableDetail: isSystemdUnavailableDetailMock,
52+
renderSystemdUnavailableHints: renderSystemdUnavailableHintsMock,
5153
}));
5254

5355
vi.mock("../../infra/wsl.js", () => ({
@@ -87,6 +89,8 @@ describe("printDaemonStatus", () => {
8789
runtime.log.mockReset();
8890
runtime.error.mockReset();
8991
resolveControlUiLinksMock.mockClear();
92+
isSystemdUnavailableDetailMock.mockReset().mockReturnValue(false);
93+
renderSystemdUnavailableHintsMock.mockReset().mockReturnValue([]);
9094
});
9195

9296
it("prints stale gateway pid guidance when runtime does not own the listener", () => {
@@ -506,4 +510,43 @@ describe("printDaemonStatus", () => {
506510
expectMockLineContains(runtime.log, "ai.openclaw.gateway.rescue");
507511
expect(runtime.error).not.toHaveBeenCalled();
508512
});
513+
514+
it("does not print systemd user-service hints when a gateway responds", () => {
515+
const platform = vi.spyOn(process, "platform", "get").mockReturnValue("linux");
516+
isSystemdUnavailableDetailMock.mockReturnValue(true);
517+
renderSystemdUnavailableHintsMock.mockReturnValue(["run loginctl enable-linger"]);
518+
519+
try {
520+
printDaemonStatus(
521+
{
522+
service: {
523+
label: "systemd user",
524+
loaded: false,
525+
loadedText: "not loaded",
526+
notLoadedText: "not loaded",
527+
runtime: { status: "unknown", detail: "systemd user services unavailable" },
528+
},
529+
rpc: {
530+
ok: true,
531+
url: "ws://127.0.0.1:18789",
532+
server: { version: "2026.5.12" },
533+
},
534+
port: {
535+
port: 18789,
536+
status: "busy",
537+
listeners: [],
538+
hints: [],
539+
},
540+
extraServices: [],
541+
},
542+
{ json: false },
543+
);
544+
} finally {
545+
platform.mockRestore();
546+
}
547+
548+
const errors = runtime.error.mock.calls.map(([line]) => line).join("\n");
549+
expect(errors).not.toContain("systemd user services unavailable");
550+
expect(errors).not.toContain("run loginctl enable-linger");
551+
});
509552
});

src/cli/daemon-cli/status.print.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,9 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean })
320320
}
321321

322322
const systemdUnavailable =
323-
process.platform === "linux" && isSystemdUnavailableDetail(service.runtime?.detail);
323+
process.platform === "linux" &&
324+
rpc?.ok !== true &&
325+
isSystemdUnavailableDetail(service.runtime?.detail);
324326
if (systemdUnavailable) {
325327
const container = Boolean(
326328
resolveDaemonContainerContext(service.command?.environment ?? process.env),

0 commit comments

Comments
 (0)