chore: migrate to oxlint and oxfmt
Co-authored-by: Christoph Nakazawa <christoph.pojer@gmail.com>
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
import type { Command } from "commander";
|
||||
import { callGateway } from "../../gateway/call.js";
|
||||
import {
|
||||
GATEWAY_CLIENT_MODES,
|
||||
GATEWAY_CLIENT_NAMES,
|
||||
} from "../../utils/message-channel.js";
|
||||
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../utils/message-channel.js";
|
||||
import { withProgress } from "../progress.js";
|
||||
|
||||
export type GatewayRpcOpts = {
|
||||
@@ -17,21 +14,14 @@ export type GatewayRpcOpts = {
|
||||
|
||||
export const gatewayCallOpts = (cmd: Command) =>
|
||||
cmd
|
||||
.option(
|
||||
"--url <url>",
|
||||
"Gateway WebSocket URL (defaults to gateway.remote.url when configured)",
|
||||
)
|
||||
.option("--url <url>", "Gateway WebSocket URL (defaults to gateway.remote.url when configured)")
|
||||
.option("--token <token>", "Gateway token (if required)")
|
||||
.option("--password <password>", "Gateway password (password auth)")
|
||||
.option("--timeout <ms>", "Timeout in ms", "10000")
|
||||
.option("--expect-final", "Wait for final response (agent)", false)
|
||||
.option("--json", "Output JSON", false);
|
||||
|
||||
export const callGatewayCli = async (
|
||||
method: string,
|
||||
opts: GatewayRpcOpts,
|
||||
params?: unknown,
|
||||
) =>
|
||||
export const callGatewayCli = async (method: string, opts: GatewayRpcOpts, params?: unknown) =>
|
||||
withProgress(
|
||||
{
|
||||
label: `Gateway ${method}`,
|
||||
|
||||
@@ -18,15 +18,9 @@ const DEV_TEMPLATE_DIR = path.resolve(
|
||||
"../../../docs/reference/templates",
|
||||
);
|
||||
|
||||
async function loadDevTemplate(
|
||||
name: string,
|
||||
fallback: string,
|
||||
): Promise<string> {
|
||||
async function loadDevTemplate(name: string, fallback: string): Promise<string> {
|
||||
try {
|
||||
const raw = await fs.promises.readFile(
|
||||
path.join(DEV_TEMPLATE_DIR, name),
|
||||
"utf-8",
|
||||
);
|
||||
const raw = await fs.promises.readFile(path.join(DEV_TEMPLATE_DIR, name), "utf-8");
|
||||
if (!raw.startsWith("---")) return raw;
|
||||
const endIndex = raw.indexOf("\n---", 3);
|
||||
if (endIndex === -1) return raw;
|
||||
@@ -36,9 +30,7 @@ async function loadDevTemplate(
|
||||
}
|
||||
}
|
||||
|
||||
const resolveDevWorkspaceDir = (
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): string => {
|
||||
const resolveDevWorkspaceDir = (env: NodeJS.ProcessEnv = process.env): string => {
|
||||
const baseDir = resolveDefaultAgentWorkspaceDir(env, os.homedir);
|
||||
const profile = env.CLAWDBOT_PROFILE?.trim().toLowerCase();
|
||||
if (profile === "dev") return baseDir;
|
||||
|
||||
@@ -6,10 +6,7 @@ export type GatewayDiscoverOpts = {
|
||||
json?: boolean;
|
||||
};
|
||||
|
||||
export function parseDiscoverTimeoutMs(
|
||||
raw: unknown,
|
||||
fallbackMs: number,
|
||||
): number {
|
||||
export function parseDiscoverTimeoutMs(raw: unknown, fallbackMs: number): number {
|
||||
if (raw === undefined || raw === null) return fallbackMs;
|
||||
const value =
|
||||
typeof raw === "string"
|
||||
@@ -38,9 +35,7 @@ export function pickGatewayPort(beacon: GatewayBonjourBeacon): number {
|
||||
return port > 0 ? port : 18789;
|
||||
}
|
||||
|
||||
export function dedupeBeacons(
|
||||
beacons: GatewayBonjourBeacon[],
|
||||
): GatewayBonjourBeacon[] {
|
||||
export function dedupeBeacons(beacons: GatewayBonjourBeacon[]): GatewayBonjourBeacon[] {
|
||||
const out: GatewayBonjourBeacon[] = [];
|
||||
const seen = new Set<string>();
|
||||
for (const b of beacons) {
|
||||
@@ -61,15 +56,8 @@ export function dedupeBeacons(
|
||||
return out;
|
||||
}
|
||||
|
||||
export function renderBeaconLines(
|
||||
beacon: GatewayBonjourBeacon,
|
||||
rich: boolean,
|
||||
): string[] {
|
||||
const nameRaw = (
|
||||
beacon.displayName ||
|
||||
beacon.instanceName ||
|
||||
"Gateway"
|
||||
).trim();
|
||||
export function renderBeaconLines(beacon: GatewayBonjourBeacon, rich: boolean): string[] {
|
||||
const nameRaw = (beacon.displayName || beacon.instanceName || "Gateway").trim();
|
||||
const domainRaw = (beacon.domain || "local.").trim();
|
||||
|
||||
const title = colorize(rich, theme.accentBright, nameRaw);
|
||||
@@ -82,9 +70,7 @@ export function renderBeaconLines(
|
||||
const lines = [`- ${title} ${domain}`];
|
||||
|
||||
if (beacon.tailnetDns) {
|
||||
lines.push(
|
||||
` ${colorize(rich, theme.info, "tailnet")}: ${beacon.tailnetDns}`,
|
||||
);
|
||||
lines.push(` ${colorize(rich, theme.info, "tailnet")}: ${beacon.tailnetDns}`);
|
||||
}
|
||||
if (beacon.lanHost) {
|
||||
lines.push(` ${colorize(rich, theme.info, "lan")}: ${beacon.lanHost}`);
|
||||
@@ -94,15 +80,11 @@ export function renderBeaconLines(
|
||||
}
|
||||
|
||||
if (wsUrl) {
|
||||
lines.push(
|
||||
` ${colorize(rich, theme.muted, "ws")}: ${colorize(rich, theme.command, wsUrl)}`,
|
||||
);
|
||||
lines.push(` ${colorize(rich, theme.muted, "ws")}: ${colorize(rich, theme.command, wsUrl)}`);
|
||||
}
|
||||
if (typeof beacon.sshPort === "number" && beacon.sshPort > 0 && host) {
|
||||
const ssh = `ssh -N -L 18789:127.0.0.1:18789 <user>@${host} -p ${beacon.sshPort}`;
|
||||
lines.push(
|
||||
` ${colorize(rich, theme.muted, "ssh")}: ${colorize(rich, theme.command, ssh)}`,
|
||||
);
|
||||
lines.push(` ${colorize(rich, theme.muted, "ssh")}: ${colorize(rich, theme.command, ssh)}`);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import type { Command } from "commander";
|
||||
import { gatewayStatusCommand } from "../../commands/gateway-status.js";
|
||||
import {
|
||||
formatHealthChannelLines,
|
||||
type HealthSummary,
|
||||
} from "../../commands/health.js";
|
||||
import { formatHealthChannelLines, type HealthSummary } from "../../commands/health.js";
|
||||
import { discoverGatewayBeacons } from "../../infra/bonjour-discovery.js";
|
||||
import { WIDE_AREA_DISCOVERY_DOMAIN } from "../../infra/widearea-dns.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
@@ -28,11 +25,7 @@ export function registerGatewayCli(program: Command) {
|
||||
.description("Run the WebSocket Gateway")
|
||||
.addHelpText(
|
||||
"after",
|
||||
() =>
|
||||
`\n${theme.muted("Docs:")} ${formatDocsLink(
|
||||
"/gateway",
|
||||
"docs.clawd.bot/gateway",
|
||||
)}\n`,
|
||||
() => `\n${theme.muted("Docs:")} ${formatDocsLink("/gateway", "docs.clawd.bot/gateway")}\n`,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -48,10 +41,7 @@ export function registerGatewayCli(program: Command) {
|
||||
gateway
|
||||
.command("call")
|
||||
.description("Call a Gateway method")
|
||||
.argument(
|
||||
"<method>",
|
||||
"Method name (health/status/system-presence/cron.*)",
|
||||
)
|
||||
.argument("<method>", "Method name (health/status/system-presence/cron.*)")
|
||||
.option("--params <json>", "JSON object string for params", "{}")
|
||||
.action(async (method, opts) => {
|
||||
try {
|
||||
@@ -86,11 +76,8 @@ export function registerGatewayCli(program: Command) {
|
||||
}
|
||||
const rich = isRich();
|
||||
const obj =
|
||||
result && typeof result === "object"
|
||||
? (result as Record<string, unknown>)
|
||||
: {};
|
||||
const durationMs =
|
||||
typeof obj.durationMs === "number" ? obj.durationMs : null;
|
||||
result && typeof result === "object" ? (result as Record<string, unknown>) : {};
|
||||
const durationMs = typeof obj.durationMs === "number" ? obj.durationMs : null;
|
||||
defaultRuntime.log(colorize(rich, theme.heading, "Gateway Health"));
|
||||
defaultRuntime.log(
|
||||
`${colorize(rich, theme.success, "OK")}${durationMs != null ? ` (${durationMs}ms)` : ""}`,
|
||||
@@ -109,23 +96,11 @@ export function registerGatewayCli(program: Command) {
|
||||
|
||||
gateway
|
||||
.command("status")
|
||||
.description(
|
||||
"Show gateway reachability + discovery + health + status summary (local + remote)",
|
||||
)
|
||||
.option(
|
||||
"--url <url>",
|
||||
"Explicit Gateway WebSocket URL (still probes localhost)",
|
||||
)
|
||||
.option(
|
||||
"--ssh <target>",
|
||||
"SSH target for remote gateway tunnel (user@host or user@host:port)",
|
||||
)
|
||||
.description("Show gateway reachability + discovery + health + status summary (local + remote)")
|
||||
.option("--url <url>", "Explicit Gateway WebSocket URL (still probes localhost)")
|
||||
.option("--ssh <target>", "SSH target for remote gateway tunnel (user@host or user@host:port)")
|
||||
.option("--ssh-identity <path>", "SSH identity file path")
|
||||
.option(
|
||||
"--ssh-auto",
|
||||
"Try to derive an SSH target from Bonjour discovery",
|
||||
false,
|
||||
)
|
||||
.option("--ssh-auto", "Try to derive an SSH target from Bonjour discovery", false)
|
||||
.option("--token <token>", "Gateway token (applies to all probes)")
|
||||
.option("--password <password>", "Gateway password (applies to all probes)")
|
||||
.option("--timeout <ms>", "Overall probe budget in ms", "3000")
|
||||
|
||||
@@ -27,9 +27,7 @@ export async function runGatewayLoop(params: {
|
||||
}
|
||||
shuttingDown = true;
|
||||
const isRestart = action === "restart";
|
||||
gatewayLog.info(
|
||||
`received ${signal}; ${isRestart ? "restarting" : "shutting down"}`,
|
||||
);
|
||||
gatewayLog.info(`received ${signal}; ${isRestart ? "restarting" : "shutting down"}`);
|
||||
|
||||
const forceExitTimer = setTimeout(() => {
|
||||
gatewayLog.error("shutdown timed out; exiting without full cleanup");
|
||||
|
||||
@@ -15,10 +15,7 @@ import { setGatewayWsLogStyle } from "../../gateway/ws-logging.js";
|
||||
import { setVerbose } from "../../globals.js";
|
||||
import { GatewayLockError } from "../../infra/gateway-lock.js";
|
||||
import { formatPortDiagnostics, inspectPortUsage } from "../../infra/ports.js";
|
||||
import {
|
||||
createSubsystemLogger,
|
||||
setConsoleSubsystemFilter,
|
||||
} from "../../logging.js";
|
||||
import { createSubsystemLogger, setConsoleSubsystemFilter } from "../../logging.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
import { forceFreePortAndWait } from "../ports.js";
|
||||
import { ensureDevGatewayConfig } from "./dev.js";
|
||||
@@ -57,12 +54,8 @@ type GatewayRunParams = {
|
||||
|
||||
const gatewayLog = createSubsystemLogger("gateway");
|
||||
|
||||
async function runGatewayCommand(
|
||||
opts: GatewayRunOpts,
|
||||
params: GatewayRunParams = {},
|
||||
) {
|
||||
const isDevProfile =
|
||||
process.env.CLAWDBOT_PROFILE?.trim().toLowerCase() === "dev";
|
||||
async function runGatewayCommand(opts: GatewayRunOpts, params: GatewayRunParams = {}) {
|
||||
const isDevProfile = process.env.CLAWDBOT_PROFILE?.trim().toLowerCase() === "dev";
|
||||
const devMode = Boolean(opts.dev) || isDevProfile;
|
||||
if (opts.reset && !devMode) {
|
||||
defaultRuntime.error("Use --reset with --dev.");
|
||||
@@ -81,9 +74,7 @@ async function runGatewayCommand(
|
||||
setConsoleSubsystemFilter(["agent/claude-cli"]);
|
||||
process.env.CLAWDBOT_CLAUDE_CLI_LOG_OUTPUT = "1";
|
||||
}
|
||||
const wsLogRaw = (opts.compact ? "compact" : opts.wsLog) as
|
||||
| string
|
||||
| undefined;
|
||||
const wsLogRaw = (opts.compact ? "compact" : opts.wsLog) as string | undefined;
|
||||
const wsLogStyle: GatewayWsLogStyle =
|
||||
wsLogRaw === "compact" ? "compact" : wsLogRaw === "full" ? "full" : "auto";
|
||||
if (
|
||||
@@ -122,12 +113,11 @@ async function runGatewayCommand(
|
||||
}
|
||||
if (opts.force) {
|
||||
try {
|
||||
const { killed, waitedMs, escalatedToSigkill } =
|
||||
await forceFreePortAndWait(port, {
|
||||
timeoutMs: 2000,
|
||||
intervalMs: 100,
|
||||
sigtermTimeoutMs: 700,
|
||||
});
|
||||
const { killed, waitedMs, escalatedToSigkill } = await forceFreePortAndWait(port, {
|
||||
timeoutMs: 2000,
|
||||
intervalMs: 100,
|
||||
sigtermTimeoutMs: 700,
|
||||
});
|
||||
if (killed.length === 0) {
|
||||
gatewayLog.info(`force: no listeners on port ${port}`);
|
||||
} else {
|
||||
@@ -137,14 +127,10 @@ async function runGatewayCommand(
|
||||
);
|
||||
}
|
||||
if (escalatedToSigkill) {
|
||||
gatewayLog.info(
|
||||
`force: escalated to SIGKILL while freeing port ${port}`,
|
||||
);
|
||||
gatewayLog.info(`force: escalated to SIGKILL while freeing port ${port}`);
|
||||
}
|
||||
if (waitedMs > 0) {
|
||||
gatewayLog.info(
|
||||
`force: waited ${waitedMs}ms for port ${port} to free`,
|
||||
);
|
||||
gatewayLog.info(`force: waited ${waitedMs}ms for port ${port} to free`);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -167,15 +153,11 @@ async function runGatewayCommand(
|
||||
}
|
||||
const tailscaleRaw = toOptionString(opts.tailscale);
|
||||
const tailscaleMode =
|
||||
tailscaleRaw === "off" ||
|
||||
tailscaleRaw === "serve" ||
|
||||
tailscaleRaw === "funnel"
|
||||
tailscaleRaw === "off" || tailscaleRaw === "serve" || tailscaleRaw === "funnel"
|
||||
? tailscaleRaw
|
||||
: null;
|
||||
if (tailscaleRaw && !tailscaleMode) {
|
||||
defaultRuntime.error(
|
||||
'Invalid --tailscale (use "off", "serve", or "funnel")',
|
||||
);
|
||||
defaultRuntime.error('Invalid --tailscale (use "off", "serve", or "funnel")');
|
||||
defaultRuntime.exit(1);
|
||||
return;
|
||||
}
|
||||
@@ -199,16 +181,11 @@ async function runGatewayCommand(
|
||||
}
|
||||
const bindRaw = toOptionString(opts.bind) ?? cfg.gateway?.bind ?? "loopback";
|
||||
const bind =
|
||||
bindRaw === "loopback" ||
|
||||
bindRaw === "lan" ||
|
||||
bindRaw === "auto" ||
|
||||
bindRaw === "custom"
|
||||
bindRaw === "loopback" || bindRaw === "lan" || bindRaw === "auto" || bindRaw === "custom"
|
||||
? bindRaw
|
||||
: null;
|
||||
if (!bind) {
|
||||
defaultRuntime.error(
|
||||
'Invalid --bind (use "loopback", "lan", "auto", or "custom")',
|
||||
);
|
||||
defaultRuntime.error('Invalid --bind (use "loopback", "lan", "auto", or "custom")');
|
||||
defaultRuntime.exit(1);
|
||||
return;
|
||||
}
|
||||
@@ -231,9 +208,7 @@ async function runGatewayCommand(
|
||||
const passwordValue = resolvedAuth.password;
|
||||
const authHints: string[] = [];
|
||||
if (miskeys.hasGatewayToken) {
|
||||
authHints.push(
|
||||
'Found "gateway.token" in config. Use "gateway.auth.token" instead.',
|
||||
);
|
||||
authHints.push('Found "gateway.token" in config. Use "gateway.auth.token" instead.');
|
||||
}
|
||||
if (miskeys.hasRemoteToken) {
|
||||
authHints.push(
|
||||
@@ -306,9 +281,7 @@ async function runGatewayCommand(
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof GatewayLockError ||
|
||||
(err &&
|
||||
typeof err === "object" &&
|
||||
(err as { name?: string }).name === "GatewayLockError")
|
||||
(err && typeof err === "object" && (err as { name?: string }).name === "GatewayLockError")
|
||||
) {
|
||||
const errMessage = describeUnknownError(err);
|
||||
defaultRuntime.error(
|
||||
@@ -333,10 +306,7 @@ async function runGatewayCommand(
|
||||
}
|
||||
}
|
||||
|
||||
export function addGatewayRunCommand(
|
||||
cmd: Command,
|
||||
params: GatewayRunParams = {},
|
||||
): Command {
|
||||
export function addGatewayRunCommand(cmd: Command, params: GatewayRunParams = {}): Command {
|
||||
return cmd
|
||||
.option("--port <port>", "Port for the gateway WebSocket")
|
||||
.option(
|
||||
@@ -349,10 +319,7 @@ export function addGatewayRunCommand(
|
||||
)
|
||||
.option("--auth <mode>", 'Gateway auth mode ("token"|"password")')
|
||||
.option("--password <password>", "Password for auth mode=password")
|
||||
.option(
|
||||
"--tailscale <mode>",
|
||||
'Tailscale exposure mode ("off"|"serve"|"funnel")',
|
||||
)
|
||||
.option("--tailscale <mode>", 'Tailscale exposure mode ("off"|"serve"|"funnel")')
|
||||
.option(
|
||||
"--tailscale-reset-on-exit",
|
||||
"Reset Tailscale serve/funnel configuration on shutdown",
|
||||
@@ -363,32 +330,20 @@ export function addGatewayRunCommand(
|
||||
"Allow gateway start without gateway.mode=local in config",
|
||||
false,
|
||||
)
|
||||
.option(
|
||||
"--dev",
|
||||
"Create a dev config + workspace if missing (no BOOTSTRAP.md)",
|
||||
false,
|
||||
)
|
||||
.option("--dev", "Create a dev config + workspace if missing (no BOOTSTRAP.md)", false)
|
||||
.option(
|
||||
"--reset",
|
||||
"Reset dev config + credentials + sessions + workspace (requires --dev)",
|
||||
false,
|
||||
)
|
||||
.option(
|
||||
"--force",
|
||||
"Kill any existing listener on the target port before starting",
|
||||
false,
|
||||
)
|
||||
.option("--force", "Kill any existing listener on the target port before starting", false)
|
||||
.option("--verbose", "Verbose logging to stdout/stderr", false)
|
||||
.option(
|
||||
"--claude-cli-logs",
|
||||
"Only show claude-cli logs in the console (includes stdout/stderr)",
|
||||
false,
|
||||
)
|
||||
.option(
|
||||
"--ws-log <style>",
|
||||
'WebSocket log style ("auto"|"full"|"compact")',
|
||||
"auto",
|
||||
)
|
||||
.option("--ws-log <style>", 'WebSocket log style ("auto"|"full"|"compact")', "auto")
|
||||
.option("--compact", 'Alias for "--ws-log compact"', false)
|
||||
.option("--raw-stream", "Log raw model stream events to jsonl", false)
|
||||
.option("--raw-stream-path <path>", "Raw stream jsonl path")
|
||||
|
||||
@@ -22,8 +22,7 @@ export function parsePort(raw: unknown): number | null {
|
||||
|
||||
export const toOptionString = (value: unknown): string | undefined => {
|
||||
if (typeof value === "string") return value;
|
||||
if (typeof value === "number" || typeof value === "bigint")
|
||||
return value.toString();
|
||||
if (typeof value === "number" || typeof value === "bigint") return value.toString();
|
||||
return undefined;
|
||||
};
|
||||
|
||||
@@ -59,15 +58,11 @@ export function extractGatewayMiskeys(parsed: unknown): {
|
||||
const hasGatewayToken = "token" in (gateway as Record<string, unknown>);
|
||||
const remote = (gateway as Record<string, unknown>).remote;
|
||||
const hasRemoteToken =
|
||||
remote && typeof remote === "object"
|
||||
? "token" in (remote as Record<string, unknown>)
|
||||
: false;
|
||||
remote && typeof remote === "object" ? "token" in (remote as Record<string, unknown>) : false;
|
||||
return { hasGatewayToken, hasRemoteToken };
|
||||
}
|
||||
|
||||
export function renderGatewayServiceStopHints(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): string[] {
|
||||
export function renderGatewayServiceStopHints(env: NodeJS.ProcessEnv = process.env): string[] {
|
||||
const profile = env.CLAWDBOT_PROFILE;
|
||||
switch (process.platform) {
|
||||
case "darwin":
|
||||
|
||||
Reference in New Issue
Block a user