diff --git a/src/cli/daemon-cli/install.ts b/src/cli/daemon-cli/install.ts index d31f14c08fa..64cb8d52de3 100644 --- a/src/cli/daemon-cli/install.ts +++ b/src/cli/daemon-cli/install.ts @@ -94,12 +94,12 @@ export async function runDaemonInstall(opts: DaemonInstallOptions) { const cfg = configSnapshot.valid ? configSnapshot.sourceConfig : configSnapshot.config; const portOverride = parsePort(opts.port); if (opts.port !== undefined && portOverride === null) { - fail("Invalid port"); + fail("Invalid --port. Use a port number from 1 to 65535, for example 18789."); return; } const port = portOverride ?? resolveGatewayPort(cfg); - if (!Number.isFinite(port) || port <= 0) { - fail("Invalid port"); + if (!Number.isFinite(port) || port <= 0 || port > 65_535) { + fail("Invalid Gateway port in config. Set gateway.port to a number from 1 to 65535."); return; } const runtimeRaw = opts.runtime ? opts.runtime : DEFAULT_GATEWAY_DAEMON_RUNTIME; diff --git a/src/cli/node-cli/daemon.ts b/src/cli/node-cli/daemon.ts index 7f85b9ce2ff..a964347de8b 100644 --- a/src/cli/node-cli/daemon.ts +++ b/src/cli/node-cli/daemon.ts @@ -94,8 +94,8 @@ export async function runNodeDaemonInstall(opts: NodeDaemonInstallOptions) { const config = await loadNodeHostConfig(); const { host, port } = resolveNodeDefaults(opts, config); - if (!Number.isFinite(port ?? Number.NaN) || (port ?? 0) <= 0) { - fail("Invalid port"); + if (!Number.isFinite(port ?? Number.NaN) || (port ?? 0) <= 0 || (port ?? 0) > 65_535) { + fail("Invalid node host port. Use a port number from 1 to 65535."); return; } diff --git a/src/commands/channels.add.test.ts b/src/commands/channels.add.test.ts index 66f3b38e326..47b06988afe 100644 --- a/src/commands/channels.add.test.ts +++ b/src/commands/channels.add.test.ts @@ -614,7 +614,9 @@ describe("channelsAddCommand", () => { }), }), ); - expect(runtime.error).not.toHaveBeenCalledWith("Channel telegram does not support add."); + expect(runtime.error).not.toHaveBeenCalledWith( + expect.stringContaining("Channel telegram does not support non-interactive add"), + ); expect(runtime.exit).not.toHaveBeenCalled(); }); @@ -665,7 +667,9 @@ describe("channelsAddCommand", () => { }), }), ); - expect(runtime.error).not.toHaveBeenCalledWith("Channel telegram does not support add."); + expect(runtime.error).not.toHaveBeenCalledWith( + expect.stringContaining("Channel telegram does not support non-interactive add"), + ); expect(runtime.exit).not.toHaveBeenCalled(); }); diff --git a/src/commands/configure.gateway.ts b/src/commands/configure.gateway.ts index 9e73d5cc73c..3c5c78780a0 100644 --- a/src/commands/configure.gateway.ts +++ b/src/commands/configure.gateway.ts @@ -26,6 +26,14 @@ import { type GatewayAuthChoice = "token" | "password" | "trusted-proxy"; type GatewayTokenInputMode = "plaintext" | "ref"; +function validateGatewayPortInput(value: unknown): string | undefined { + const port = Number(typeof value === "string" ? value.trim() : value); + if (!Number.isInteger(port) || port < 1 || port > 65_535) { + return "Use a port number from 1 to 65535, for example 18789."; + } + return undefined; +} + export async function promptGatewayConfig( cfg: OpenClawConfig, runtime: RuntimeEnv, @@ -38,7 +46,7 @@ export async function promptGatewayConfig( await text({ message: "Gateway port", initialValue: String(resolveGatewayPort(cfg)), - validate: (value) => (Number.isFinite(Number(value)) ? undefined : "Invalid port"), + validate: validateGatewayPortInput, }), runtime, ); @@ -93,9 +101,9 @@ export async function promptGatewayConfig( let authMode = guardCancel( await select({ - message: "Gateway auth", + message: "Gateway access protection", options: [ - { value: "token", label: "Token", hint: "Recommended default" }, + { value: "token", label: "Token (recommended)", hint: "Recommended default" }, { value: "password", label: "Password" }, { value: "trusted-proxy", diff --git a/src/wizard/setup.finalize.test.ts b/src/wizard/setup.finalize.test.ts index 070540faddf..d386fcd0e0b 100644 --- a/src/wizard/setup.finalize.test.ts +++ b/src/wizard/setup.finalize.test.ts @@ -278,7 +278,7 @@ describe("finalizeSetupWizard", () => { process.env.OPENCLAW_GATEWAY_PASSWORD = "resolved-gateway-password"; // pragma: allowlist secret resolveSetupSecretInputString.mockResolvedValueOnce("resolved-gateway-password"); const select = vi.fn(async (params: { message: string }) => { - if (params.message === "How do you want to hatch your bot?") { + if (params.message === "Choose your first chat surface") { return "tui"; } return "later"; @@ -356,7 +356,7 @@ describe("finalizeSetupWizard", () => { it("bounds the bootstrap hatch TUI run timeout", async () => { vi.spyOn(fs, "access").mockResolvedValueOnce(undefined); const select = vi.fn(async (params: { message: string }) => { - if (params.message === "How do you want to hatch your bot?") { + if (params.message === "Choose your first chat surface") { return "tui"; } return "later"; @@ -401,7 +401,7 @@ describe("finalizeSetupWizard", () => { it("restores terminal state after failed TUI hatch", async () => { launchTuiCli.mockRejectedValueOnce(new Error("TUI exited with code 1")); const select = vi.fn(async (params: { message: string }) => { - if (params.message === "How do you want to hatch your bot?") { + if (params.message === "Choose your first chat surface") { return "tui"; } return "later"; diff --git a/src/wizard/setup.test.ts b/src/wizard/setup.test.ts index 9c03c775b46..25e0f759089 100644 --- a/src/wizard/setup.test.ts +++ b/src/wizard/setup.test.ts @@ -67,7 +67,7 @@ const finalizeSetupWizard = vi.hoisted(() => } const hatch = await options.prompter.select({ - message: "How do you want to hatch your bot?", + message: "Choose your first chat surface", options: [], }); if (hatch !== "tui") { @@ -346,13 +346,13 @@ describe("runSetupWizard", () => { const caseDir = await makeCaseDir("provider-missing-id-"); const select = vi.fn(async ({ message }: WizardSelectParams) => { - if (message === "Select setup mode") { + if (message === "Setup mode") { return "quickstart"; } if (message === "Select channel (QuickStart)") { return "__skip__"; } - if (message === "How do you want to hatch your bot?") { + if (message === "Choose your first chat surface") { return "skip"; } return "skip"; @@ -543,7 +543,7 @@ describe("runSetupWizard", () => { } const select = vi.fn(async (opts: WizardSelectParams) => { - if (opts.message === "How do you want to hatch your bot?") { + if (opts.message === "Choose your first chat surface") { return "tui"; } return "quickstart";