Skip to content

Commit 791c083

Browse files
committed
fix: extend Windows daemon onboarding health budget
1 parent 8806ef8 commit 791c083

2 files changed

Lines changed: 80 additions & 3 deletions

File tree

src/commands/onboard-non-interactive.gateway.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,49 @@ describe("onboard (non-interactive): gateway and remote auth", () => {
520520
});
521521
}, 60_000);
522522

523+
it("uses a longer Windows health deadline when daemon install was requested", async () => {
524+
await withStateDir("state-local-daemon-health-win-", async (stateDir) => {
525+
let capturedDeadlineMs: number | undefined;
526+
let capturedProbeTimeoutMs: number | undefined;
527+
waitForGatewayReachableMock = vi.fn(
528+
async (params: {
529+
url: string;
530+
token?: string;
531+
password?: string;
532+
deadlineMs?: number;
533+
probeTimeoutMs?: number;
534+
}) => {
535+
capturedDeadlineMs = params.deadlineMs;
536+
capturedProbeTimeoutMs = params.probeTimeoutMs;
537+
return { ok: true };
538+
},
539+
);
540+
541+
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
542+
try {
543+
await runNonInteractiveSetup(
544+
{
545+
nonInteractive: true,
546+
mode: "local",
547+
workspace: path.join(stateDir, "openclaw"),
548+
authChoice: "skip",
549+
skipSkills: true,
550+
skipHealth: false,
551+
installDaemon: true,
552+
gatewayBind: "loopback",
553+
},
554+
runtime,
555+
);
556+
} finally {
557+
platformSpy.mockRestore();
558+
}
559+
560+
expect(installGatewayDaemonNonInteractiveMock).toHaveBeenCalledTimes(1);
561+
expect(capturedDeadlineMs).toBe(90_000);
562+
expect(capturedProbeTimeoutMs).toBe(15_000);
563+
});
564+
}, 60_000);
565+
523566
it("emits a daemon-install failure when Linux user systemd is unavailable", async () => {
524567
await withStateDir("state-local-daemon-install-json-fail-", async (stateDir) => {
525568
installGatewayDaemonNonInteractiveMock.mockResolvedValueOnce({

src/commands/onboard-non-interactive/local.ts

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,29 @@ import { resolveNonInteractiveWorkspaceDir } from "./local/workspace.js";
2626
const INSTALL_DAEMON_HEALTH_DEADLINE_MS = 45_000;
2727
const ATTACH_EXISTING_GATEWAY_HEALTH_DEADLINE_MS = 15_000;
2828
const INSTALL_DAEMON_HEALTH_PROBE_TIMEOUT_MS = 10_000;
29+
const WINDOWS_INSTALL_DAEMON_HEALTH_DEADLINE_MS = 90_000;
30+
const WINDOWS_INSTALL_DAEMON_HEALTH_PROBE_TIMEOUT_MS = 15_000;
31+
const INSTALL_DAEMON_HEALTH_COMMAND_TIMEOUT_MS = 10_000;
32+
const WINDOWS_INSTALL_DAEMON_HEALTH_COMMAND_TIMEOUT_MS = 30_000;
33+
34+
function resolveInstallDaemonGatewayHealthTiming(): {
35+
deadlineMs: number;
36+
probeTimeoutMs: number;
37+
healthCommandTimeoutMs: number;
38+
} {
39+
if (process.platform === "win32") {
40+
return {
41+
deadlineMs: WINDOWS_INSTALL_DAEMON_HEALTH_DEADLINE_MS,
42+
probeTimeoutMs: WINDOWS_INSTALL_DAEMON_HEALTH_PROBE_TIMEOUT_MS,
43+
healthCommandTimeoutMs: WINDOWS_INSTALL_DAEMON_HEALTH_COMMAND_TIMEOUT_MS,
44+
};
45+
}
46+
return {
47+
deadlineMs: INSTALL_DAEMON_HEALTH_DEADLINE_MS,
48+
probeTimeoutMs: INSTALL_DAEMON_HEALTH_PROBE_TIMEOUT_MS,
49+
healthCommandTimeoutMs: INSTALL_DAEMON_HEALTH_COMMAND_TIMEOUT_MS,
50+
};
51+
}
2952

3053
async function collectGatewayHealthFailureDiagnostics(): Promise<
3154
GatewayHealthFailureDiagnostics | undefined
@@ -206,13 +229,16 @@ export async function runNonInteractiveLocalSetup(params: {
206229
customBindHost: nextConfig.gateway?.customBindHost,
207230
basePath: undefined,
208231
});
232+
const installDaemonGatewayHealthTiming = resolveInstallDaemonGatewayHealthTiming();
209233
const probe = await waitForGatewayReachable({
210234
url: links.wsUrl,
211235
token: gatewayResult.gatewayToken,
212236
deadlineMs: opts.installDaemon
213-
? INSTALL_DAEMON_HEALTH_DEADLINE_MS
237+
? installDaemonGatewayHealthTiming.deadlineMs
214238
: ATTACH_EXISTING_GATEWAY_HEALTH_DEADLINE_MS,
215-
probeTimeoutMs: opts.installDaemon ? INSTALL_DAEMON_HEALTH_PROBE_TIMEOUT_MS : undefined,
239+
probeTimeoutMs: opts.installDaemon
240+
? installDaemonGatewayHealthTiming.probeTimeoutMs
241+
: undefined,
216242
});
217243
if (!probe.ok) {
218244
const diagnostics = opts.installDaemon
@@ -246,7 +272,15 @@ export async function runNonInteractiveLocalSetup(params: {
246272
runtime.exit(1);
247273
return;
248274
}
249-
await healthCommand({ json: false, timeoutMs: 10_000 }, runtime);
275+
await healthCommand(
276+
{
277+
json: false,
278+
timeoutMs: opts.installDaemon
279+
? installDaemonGatewayHealthTiming.healthCommandTimeoutMs
280+
: 10_000,
281+
},
282+
runtime,
283+
);
250284
}
251285

252286
logNonInteractiveOnboardingJson({

0 commit comments

Comments
 (0)