mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-28 18:33:37 +00:00
fix: clarify no-daemon onboarding gateway checks
This commit is contained in:
@@ -5,7 +5,12 @@ import type { PluginWebSearchProviderEntry } from "../plugins/types.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
|
||||
const runTui = vi.hoisted(() => vi.fn(async () => {}));
|
||||
const probeGatewayReachable = vi.hoisted(() => vi.fn(async () => ({ ok: true })));
|
||||
const probeGatewayReachable = vi.hoisted(() =>
|
||||
vi.fn<() => Promise<{ ok: boolean; detail?: string }>>(async () => ({ ok: true })),
|
||||
);
|
||||
const waitForGatewayReachable = vi.hoisted(() =>
|
||||
vi.fn<() => Promise<{ ok: boolean; detail?: string }>>(async () => ({ ok: true })),
|
||||
);
|
||||
const setupWizardShellCompletion = vi.hoisted(() => vi.fn(async () => {}));
|
||||
const buildGatewayInstallPlan = vi.hoisted(() =>
|
||||
vi.fn(async () => ({
|
||||
@@ -58,7 +63,7 @@ vi.mock("../commands/onboard-helpers.js", () => ({
|
||||
httpUrl: "http://127.0.0.1:18789",
|
||||
wsUrl: "ws://127.0.0.1:18789",
|
||||
})),
|
||||
waitForGatewayReachable: vi.fn(async () => {}),
|
||||
waitForGatewayReachable,
|
||||
}));
|
||||
|
||||
vi.mock("../commands/daemon-install-helpers.js", () => ({
|
||||
@@ -233,6 +238,8 @@ describe("finalizeSetupWizard", () => {
|
||||
beforeEach(() => {
|
||||
runTui.mockClear();
|
||||
probeGatewayReachable.mockClear();
|
||||
waitForGatewayReachable.mockReset();
|
||||
waitForGatewayReachable.mockResolvedValue({ ok: true });
|
||||
setupWizardShellCompletion.mockClear();
|
||||
buildGatewayInstallPlan.mockClear();
|
||||
gatewayServiceInstall.mockClear();
|
||||
@@ -505,4 +512,48 @@ describe("finalizeSetupWizard", () => {
|
||||
"Web search",
|
||||
);
|
||||
});
|
||||
|
||||
it("shows actionable gateway guidance instead of a hard error in no-daemon onboarding", async () => {
|
||||
waitForGatewayReachable.mockResolvedValue({
|
||||
ok: false,
|
||||
detail: "gateway closed (1006 abnormal closure (no close frame)): no close reason",
|
||||
});
|
||||
probeGatewayReachable.mockResolvedValue({
|
||||
ok: false,
|
||||
detail: "gateway closed (1006 abnormal closure (no close frame)): no close reason",
|
||||
});
|
||||
const prompter = createLaterPrompter();
|
||||
const runtime = createRuntime();
|
||||
|
||||
await finalizeSetupWizard({
|
||||
flow: "quickstart",
|
||||
opts: {
|
||||
acceptRisk: true,
|
||||
authChoice: "skip",
|
||||
installDaemon: false,
|
||||
skipHealth: false,
|
||||
skipUi: false,
|
||||
},
|
||||
baseConfig: {},
|
||||
nextConfig: {},
|
||||
workspaceDir: "/tmp",
|
||||
settings: {
|
||||
port: 18789,
|
||||
bind: "loopback",
|
||||
authMode: "token",
|
||||
gatewayToken: "test-token",
|
||||
tailscaleMode: "off",
|
||||
tailscaleResetOnExit: false,
|
||||
},
|
||||
prompter,
|
||||
runtime,
|
||||
});
|
||||
|
||||
expect(runtime.error).not.toHaveBeenCalledWith("health failed");
|
||||
expect(prompter.note).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Setup was run without Gateway service install"),
|
||||
"Gateway",
|
||||
);
|
||||
expect(prompter.note).not.toHaveBeenCalledWith(expect.any(String), "Dashboard ready");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -51,6 +51,7 @@ export async function finalizeSetupWizard(
|
||||
options: FinalizeOnboardingOptions,
|
||||
): Promise<{ launchedTui: boolean }> {
|
||||
const { flow, opts, baseConfig, nextConfig, settings, prompter, runtime } = options;
|
||||
let gatewayProbe: { ok: boolean; detail?: string } = { ok: true };
|
||||
|
||||
const withWizardProgress = async <T>(
|
||||
label: string,
|
||||
@@ -232,15 +233,33 @@ export async function finalizeSetupWizard(
|
||||
basePath: undefined,
|
||||
});
|
||||
// Daemon install/restart can briefly flap the WS; wait a bit so health check doesn't false-fail.
|
||||
await waitForGatewayReachable({
|
||||
gatewayProbe = await waitForGatewayReachable({
|
||||
url: probeLinks.wsUrl,
|
||||
token: settings.gatewayToken,
|
||||
deadlineMs: 15_000,
|
||||
});
|
||||
try {
|
||||
await healthCommand({ json: false, timeoutMs: 10_000 }, runtime);
|
||||
} catch (err) {
|
||||
runtime.error(formatHealthCheckFailure(err));
|
||||
if (gatewayProbe.ok) {
|
||||
try {
|
||||
await healthCommand({ json: false, timeoutMs: 10_000 }, runtime);
|
||||
} catch (err) {
|
||||
runtime.error(formatHealthCheckFailure(err));
|
||||
await prompter.note(
|
||||
[
|
||||
"Docs:",
|
||||
"https://docs.openclaw.ai/gateway/health",
|
||||
"https://docs.openclaw.ai/gateway/troubleshooting",
|
||||
].join("\n"),
|
||||
"Health check help",
|
||||
);
|
||||
}
|
||||
} else if (installDaemon) {
|
||||
runtime.error(
|
||||
formatHealthCheckFailure(
|
||||
new Error(
|
||||
gatewayProbe.detail ?? `gateway did not become reachable at ${probeLinks.wsUrl}`,
|
||||
),
|
||||
),
|
||||
);
|
||||
await prompter.note(
|
||||
[
|
||||
"Docs:",
|
||||
@@ -249,6 +268,17 @@ export async function finalizeSetupWizard(
|
||||
].join("\n"),
|
||||
"Health check help",
|
||||
);
|
||||
} else {
|
||||
await prompter.note(
|
||||
[
|
||||
"Gateway not detected yet.",
|
||||
"Setup was run without Gateway service install, so no background gateway is expected.",
|
||||
`Start now: ${formatCliCommand("openclaw gateway run")}`,
|
||||
`Or rerun with: ${formatCliCommand("openclaw onboard --install-daemon")}`,
|
||||
`Or skip this probe next time: ${formatCliCommand("openclaw onboard --skip-health")}`,
|
||||
].join("\n"),
|
||||
"Gateway",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,11 +334,13 @@ export async function finalizeSetupWizard(
|
||||
}
|
||||
}
|
||||
|
||||
const gatewayProbe = await probeGatewayReachable({
|
||||
url: links.wsUrl,
|
||||
token: settings.authMode === "token" ? settings.gatewayToken : undefined,
|
||||
password: settings.authMode === "password" ? resolvedGatewayPassword : "",
|
||||
});
|
||||
if (opts.skipHealth || !gatewayProbe.ok) {
|
||||
gatewayProbe = await probeGatewayReachable({
|
||||
url: links.wsUrl,
|
||||
token: settings.authMode === "token" ? settings.gatewayToken : undefined,
|
||||
password: settings.authMode === "password" ? resolvedGatewayPassword : "",
|
||||
});
|
||||
}
|
||||
const gatewayStatusLine = gatewayProbe.ok
|
||||
? "Gateway: reachable"
|
||||
: `Gateway: not detected${gatewayProbe.detail ? ` (${gatewayProbe.detail})` : ""}`;
|
||||
@@ -446,6 +478,7 @@ export async function finalizeSetupWizard(
|
||||
|
||||
const shouldOpenControlUi =
|
||||
!opts.skipUi &&
|
||||
gatewayProbe.ok &&
|
||||
settings.authMode === "token" &&
|
||||
Boolean(settings.gatewayToken) &&
|
||||
hatchChoice === null;
|
||||
|
||||
Reference in New Issue
Block a user