mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 09:38:39 +00:00
fix: clarify windows onboarding gateway health
This commit is contained in:
@@ -118,6 +118,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
- Windows/install: stop auto-installing `node-llama-cpp` during normal npm CLI installs so `openclaw@latest` no longer fails on Windows while building optional local-embedding dependencies.
|
- Windows/install: stop auto-installing `node-llama-cpp` during normal npm CLI installs so `openclaw@latest` no longer fails on Windows while building optional local-embedding dependencies.
|
||||||
- Windows/update: mirror the native installer environment during global npm updates, including portable Git fallback and Windows-safe npm shell settings, so `openclaw update` works again on native Windows installs.
|
- Windows/update: mirror the native installer environment during global npm updates, including portable Git fallback and Windows-safe npm shell settings, so `openclaw update` works again on native Windows installs.
|
||||||
- Gateway/status: expose `runtimeVersion` in gateway status output so install/update smoke tests can verify the running version before and after updates.
|
- Gateway/status: expose `runtimeVersion` in gateway status output so install/update smoke tests can verify the running version before and after updates.
|
||||||
|
- Windows/onboarding: explain when non-interactive local onboarding is waiting for an already-running gateway, and surface native Scheduled Task admin requirements more clearly instead of failing with an opaque gateway timeout.
|
||||||
- Agents/text sanitization: strip leaked model control tokens (`<|...|>` and full-width `<|...|>` variants) from user-facing assistant text, preventing GLM-5 and DeepSeek internal delimiters from reaching end users. (#42173) Thanks @imwyvern.
|
- Agents/text sanitization: strip leaked model control tokens (`<|...|>` and full-width `<|...|>` variants) from user-facing assistant text, preventing GLM-5 and DeepSeek internal delimiters from reaching end users. (#42173) Thanks @imwyvern.
|
||||||
- iOS/gateway foreground recovery: reconnect immediately on foreground return after stale background sockets are torn down, so the app no longer stays disconnected until a later wake path happens. (#41384) Thanks @mbelinky.
|
- iOS/gateway foreground recovery: reconnect immediately on foreground return after stale background sockets are torn down, so the app no longer stays disconnected until a later wake path happens. (#41384) Thanks @mbelinky.
|
||||||
- Gateway/Control UI: keep dashboard auth tokens in session-scoped browser storage so same-tab refreshes preserve remote token auth without restoring long-lived localStorage token persistence, while scoping tokens to the selected gateway URL and fragment-only bootstrap flow. (#40892) thanks @velvet-shark.
|
- Gateway/Control UI: keep dashboard auth tokens in session-scoped browser storage so same-tab refreshes preserve remote token auth without restoring long-lived localStorage token persistence, while scoping tokens to the selected gateway URL and fragment-only bootstrap flow. (#40892) thanks @velvet-shark.
|
||||||
|
|||||||
@@ -95,6 +95,13 @@ openclaw onboard --non-interactive \
|
|||||||
--accept-risk
|
--accept-risk
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Non-interactive local gateway health:
|
||||||
|
|
||||||
|
- Unless you pass `--skip-health`, onboarding waits for a reachable local gateway before it exits successfully.
|
||||||
|
- `--install-daemon` starts the managed gateway install path first. Without it, you must already have a local gateway running, for example `openclaw gateway run`.
|
||||||
|
- If you only want config/workspace/bootstrap writes in automation, use `--skip-health`.
|
||||||
|
- On native Windows, `--install-daemon` currently uses Scheduled Tasks and may require running PowerShell as Administrator.
|
||||||
|
|
||||||
Interactive onboarding behavior with reference mode:
|
Interactive onboarding behavior with reference mode:
|
||||||
|
|
||||||
- Choose **Use secret reference** when prompted.
|
- Choose **Use secret reference** when prompted.
|
||||||
|
|||||||
@@ -22,6 +22,33 @@ Native Windows companion apps are planned.
|
|||||||
- [Install & updates](/install/updating)
|
- [Install & updates](/install/updating)
|
||||||
- Official WSL2 guide (Microsoft): [https://learn.microsoft.com/windows/wsl/install](https://learn.microsoft.com/windows/wsl/install)
|
- Official WSL2 guide (Microsoft): [https://learn.microsoft.com/windows/wsl/install](https://learn.microsoft.com/windows/wsl/install)
|
||||||
|
|
||||||
|
## Native Windows status
|
||||||
|
|
||||||
|
Native Windows CLI flows are improving, but WSL2 is still the recommended path.
|
||||||
|
|
||||||
|
What works well on native Windows today:
|
||||||
|
|
||||||
|
- website installer via `install.ps1`
|
||||||
|
- local CLI use such as `openclaw --version`, `openclaw doctor`, and `openclaw plugins list --json`
|
||||||
|
- embedded local-agent/provider smoke such as:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
openclaw agent --local --agent main --thinking low -m "Reply with exactly WINDOWS-HATCH-OK."
|
||||||
|
```
|
||||||
|
|
||||||
|
Current caveats:
|
||||||
|
|
||||||
|
- `openclaw onboard --non-interactive` still expects a reachable local gateway unless you pass `--skip-health`
|
||||||
|
- `openclaw onboard --non-interactive --install-daemon` and `openclaw gateway install` currently use Windows Scheduled Tasks
|
||||||
|
- on some native Windows setups, Scheduled Task install may require running PowerShell as Administrator
|
||||||
|
|
||||||
|
If you want the native CLI only, without gateway service install, use one of these:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
openclaw onboard --non-interactive --skip-health
|
||||||
|
openclaw gateway run
|
||||||
|
```
|
||||||
|
|
||||||
## Gateway
|
## Gateway
|
||||||
|
|
||||||
- [Gateway runbook](/gateway)
|
- [Gateway runbook](/gateway)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
||||||
import { makeTempWorkspace } from "../test-helpers/workspace.js";
|
import { makeTempWorkspace } from "../test-helpers/workspace.js";
|
||||||
import { captureEnv } from "../test-utils/env.js";
|
import { captureEnv } from "../test-utils/env.js";
|
||||||
import { createThrowingRuntime, readJsonFile } from "./onboard-non-interactive.test-helpers.js";
|
import { createThrowingRuntime, readJsonFile } from "./onboard-non-interactive.test-helpers.js";
|
||||||
@@ -13,6 +13,12 @@ const gatewayClientCalls: Array<{
|
|||||||
onClose?: (code: number, reason: string) => void;
|
onClose?: (code: number, reason: string) => void;
|
||||||
}> = [];
|
}> = [];
|
||||||
const ensureWorkspaceAndSessionsMock = vi.fn(async (..._args: unknown[]) => {});
|
const ensureWorkspaceAndSessionsMock = vi.fn(async (..._args: unknown[]) => {});
|
||||||
|
let waitForGatewayReachableMock:
|
||||||
|
| ((params: { url: string; token?: string; password?: string }) => Promise<{
|
||||||
|
ok: boolean;
|
||||||
|
detail?: string;
|
||||||
|
}>)
|
||||||
|
| undefined;
|
||||||
|
|
||||||
vi.mock("../gateway/client.js", () => ({
|
vi.mock("../gateway/client.js", () => ({
|
||||||
GatewayClient: class {
|
GatewayClient: class {
|
||||||
@@ -46,6 +52,10 @@ vi.mock("./onboard-helpers.js", async (importOriginal) => {
|
|||||||
return {
|
return {
|
||||||
...actual,
|
...actual,
|
||||||
ensureWorkspaceAndSessions: ensureWorkspaceAndSessionsMock,
|
ensureWorkspaceAndSessions: ensureWorkspaceAndSessionsMock,
|
||||||
|
waitForGatewayReachable: (...args: Parameters<typeof actual.waitForGatewayReachable>) =>
|
||||||
|
waitForGatewayReachableMock
|
||||||
|
? waitForGatewayReachableMock(args[0])
|
||||||
|
: actual.waitForGatewayReachable(...args),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -116,6 +126,10 @@ describe("onboard (non-interactive): gateway and remote auth", () => {
|
|||||||
envSnapshot.restore();
|
envSnapshot.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
waitForGatewayReachableMock = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
it("writes gateway token auth into config", async () => {
|
it("writes gateway token auth into config", async () => {
|
||||||
await withStateDir("state-noninteractive-", async (stateDir) => {
|
await withStateDir("state-noninteractive-", async (stateDir) => {
|
||||||
const token = "tok_test_123";
|
const token = "tok_test_123";
|
||||||
@@ -302,6 +316,33 @@ describe("onboard (non-interactive): gateway and remote auth", () => {
|
|||||||
});
|
});
|
||||||
}, 60_000);
|
}, 60_000);
|
||||||
|
|
||||||
|
it("explains local health failure when no daemon was requested", async () => {
|
||||||
|
await withStateDir("state-local-health-hint-", async (stateDir) => {
|
||||||
|
waitForGatewayReachableMock = vi.fn(async () => ({
|
||||||
|
ok: false,
|
||||||
|
detail: "socket closed: 1006 abnormal closure",
|
||||||
|
}));
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
runNonInteractiveOnboarding(
|
||||||
|
{
|
||||||
|
nonInteractive: true,
|
||||||
|
mode: "local",
|
||||||
|
workspace: path.join(stateDir, "openclaw"),
|
||||||
|
authChoice: "skip",
|
||||||
|
skipSkills: true,
|
||||||
|
skipHealth: false,
|
||||||
|
installDaemon: false,
|
||||||
|
gatewayBind: "loopback",
|
||||||
|
},
|
||||||
|
runtime,
|
||||||
|
),
|
||||||
|
).rejects.toThrow(
|
||||||
|
/only waits for an already-running gateway unless you pass --install-daemon[\s\S]*--skip-health/,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}, 60_000);
|
||||||
|
|
||||||
it("auto-generates token auth when binding LAN and persists the token", async () => {
|
it("auto-generates token auth when binding LAN and persists the token", async () => {
|
||||||
if (process.platform === "win32") {
|
if (process.platform === "win32") {
|
||||||
// Windows runner occasionally drops the temp config write in this flow; skip to keep CI green.
|
// Windows runner occasionally drops the temp config write in this flow; skip to keep CI green.
|
||||||
|
|||||||
@@ -104,11 +104,33 @@ export async function runNonInteractiveOnboardingLocal(params: {
|
|||||||
customBindHost: nextConfig.gateway?.customBindHost,
|
customBindHost: nextConfig.gateway?.customBindHost,
|
||||||
basePath: undefined,
|
basePath: undefined,
|
||||||
});
|
});
|
||||||
await waitForGatewayReachable({
|
const probe = await waitForGatewayReachable({
|
||||||
url: links.wsUrl,
|
url: links.wsUrl,
|
||||||
token: gatewayResult.gatewayToken,
|
token: gatewayResult.gatewayToken,
|
||||||
deadlineMs: 15_000,
|
deadlineMs: 15_000,
|
||||||
});
|
});
|
||||||
|
if (!probe.ok) {
|
||||||
|
const message = [
|
||||||
|
`Gateway did not become reachable at ${links.wsUrl}.`,
|
||||||
|
probe.detail ? `Last probe: ${probe.detail}` : undefined,
|
||||||
|
!opts.installDaemon
|
||||||
|
? [
|
||||||
|
"Non-interactive local onboarding only waits for an already-running gateway unless you pass --install-daemon.",
|
||||||
|
`Fix: start \`${formatCliCommand("openclaw gateway run")}\`, re-run with \`--install-daemon\`, or use \`--skip-health\`.`,
|
||||||
|
process.platform === "win32"
|
||||||
|
? "Native Windows managed gateway install currently uses Scheduled Tasks and may require running PowerShell as Administrator."
|
||||||
|
: undefined,
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join("\n")
|
||||||
|
: undefined,
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join("\n");
|
||||||
|
runtime.error(message);
|
||||||
|
runtime.exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
await healthCommand({ json: false, timeoutMs: 10_000 }, runtime);
|
await healthCommand({ json: false, timeoutMs: 10_000 }, runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user