feat(cli): hint gateway reachability for local/remote

This commit is contained in:
Peter Steinberger
2026-01-01 23:30:02 +01:00
parent a39ef7181d
commit ca81d94b90
3 changed files with 99 additions and 4 deletions

View File

@@ -37,6 +37,7 @@ import {
guardCancel,
openUrl,
printWizardHeader,
probeGatewayReachable,
randomToken,
summarizeExistingConfig,
} from "./onboard-helpers.js";
@@ -384,12 +385,42 @@ export async function runConfigureWizard(
}
}
const localUrl = "ws://127.0.0.1:18789";
const localProbe = await probeGatewayReachable({
url: localUrl,
token: process.env.CLAWDIS_GATEWAY_TOKEN,
password:
baseConfig.gateway?.auth?.password ??
process.env.CLAWDIS_GATEWAY_PASSWORD,
});
const remoteUrl = baseConfig.gateway?.remote?.url?.trim() ?? "";
const remoteProbe = remoteUrl
? await probeGatewayReachable({
url: remoteUrl,
token: baseConfig.gateway?.remote?.token,
})
: null;
const mode = guardCancel(
await select({
message: "Where will the Gateway run?",
options: [
{ value: "local", label: "Local (this machine)" },
{ value: "remote", label: "Remote (info-only)" },
{
value: "local",
label: "Local (this machine)",
hint: localProbe.ok
? `Gateway reachable (${localUrl})`
: `No gateway detected (${localUrl})`,
},
{
value: "remote",
label: "Remote (info-only)",
hint: !remoteUrl
? "No remote URL configured yet"
: remoteProbe?.ok
? `Gateway reachable (${remoteUrl})`
: `Configured but unreachable (${remoteUrl})`,
},
],
}),
runtime,

View File

@@ -11,6 +11,7 @@ import {
import type { ClawdisConfig } from "../config/config.js";
import { CONFIG_PATH_CLAWDIS } from "../config/config.js";
import { resolveSessionTranscriptsDir } from "../config/sessions.js";
import { callGateway } from "../gateway/call.js";
import { runCommandWithTimeout } from "../process/exec.js";
import type { RuntimeEnv } from "../runtime.js";
import { CONFIG_DIR, resolveUserPath } from "../utils.js";
@@ -171,4 +172,36 @@ export async function detectBinary(name: string): Promise<boolean> {
}
}
export async function probeGatewayReachable(params: {
url: string;
token?: string;
password?: string;
timeoutMs?: number;
}): Promise<{ ok: boolean; detail?: string }> {
const url = params.url.trim();
const timeoutMs = params.timeoutMs ?? 1500;
try {
await callGateway({
url,
token: params.token,
password: params.password,
method: "health",
timeoutMs,
});
return { ok: true };
} catch (err) {
return { ok: false, detail: summarizeError(err) };
}
}
function summarizeError(err: unknown): string {
const raw = String(err ?? "unknown error");
const line =
raw
.split("\n")
.map((s) => s.trim())
.find(Boolean) ?? raw;
return line.length > 120 ? `${line.slice(0, 119)}` : line;
}
export const DEFAULT_WORKSPACE = DEFAULT_AGENT_WORKSPACE_DIR;

View File

@@ -37,6 +37,7 @@ import {
handleReset,
openUrl,
printWizardHeader,
probeGatewayReachable,
randomToken,
summarizeExistingConfig,
} from "./onboard-helpers.js";
@@ -113,14 +114,44 @@ export async function runInteractiveOnboarding(
}
}
const localUrl = "ws://127.0.0.1:18789";
const localProbe = await probeGatewayReachable({
url: localUrl,
token: process.env.CLAWDIS_GATEWAY_TOKEN,
password:
baseConfig.gateway?.auth?.password ??
process.env.CLAWDIS_GATEWAY_PASSWORD,
});
const remoteUrl = baseConfig.gateway?.remote?.url?.trim() ?? "";
const remoteProbe = remoteUrl
? await probeGatewayReachable({
url: remoteUrl,
token: baseConfig.gateway?.remote?.token,
})
: null;
const mode =
opts.mode ??
(guardCancel(
await select({
message: "Where will the Gateway run?",
options: [
{ value: "local", label: "Local (this machine)" },
{ value: "remote", label: "Remote (info-only)" },
{
value: "local",
label: "Local (this machine)",
hint: localProbe.ok
? `Gateway reachable (${localUrl})`
: `No gateway detected (${localUrl})`,
},
{
value: "remote",
label: "Remote (info-only)",
hint: !remoteUrl
? "No remote URL configured yet"
: remoteProbe?.ok
? `Gateway reachable (${remoteUrl})`
: `Configured but unreachable (${remoteUrl})`,
},
],
}),
runtime,