fix(cli): explain port and gateway prompts

This commit is contained in:
Vincent Koc
2026-05-10 06:35:20 +08:00
parent e1a7ee6b2b
commit 554acb85a4
6 changed files with 29 additions and 17 deletions

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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();
});

View File

@@ -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",

View File

@@ -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";

View File

@@ -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<unknown>) => {
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<unknown>) => {
if (opts.message === "How do you want to hatch your bot?") {
if (opts.message === "Choose your first chat surface") {
return "tui";
}
return "quickstart";