chore: rename relay to gateway

This commit is contained in:
Peter Steinberger
2025-12-09 18:00:01 +00:00
parent bc3a14cde2
commit a3bf2bdd8c
50 changed files with 2022 additions and 2570 deletions

View File

@@ -8,7 +8,7 @@ import type {
} from "@mariozechner/pi-ai";
import { piSpec } from "../agents/pi.js";
import type { AgentMeta, AgentToolResult } from "../agents/types.js";
import type { WarelayConfig } from "../config/config.js";
import type { ClawdisConfig } from "../config/config.js";
import { isVerbose, logVerbose } from "../globals.js";
import { emitAgentEvent } from "../infra/agent-events.js";
import { logError } from "../logger.js";
@@ -141,7 +141,7 @@ function extractAssistantTextLoosely(raw: string): string | undefined {
return last ? last.replace(/\\n/g, "\n").trim() : undefined;
}
type CommandReplyConfig = NonNullable<WarelayConfig["inbound"]>["reply"] & {
type CommandReplyConfig = NonNullable<ClawdisConfig["inbound"]>["reply"] & {
mode: "command";
};

View File

@@ -3,7 +3,7 @@ import crypto from "node:crypto";
import { lookupContextTokens } from "../agents/context.js";
import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL } from "../agents/defaults.js";
import { resolveBundledPiBinary } from "../agents/pi-path.js";
import { loadConfig, type WarelayConfig } from "../config/config.js";
import { loadConfig, type ClawdisConfig } from "../config/config.js";
import {
DEFAULT_IDLE_MINUTES,
DEFAULT_RESET_TRIGGER,
@@ -15,7 +15,7 @@ import {
} from "../config/sessions.js";
import { isVerbose, logVerbose } from "../globals.js";
import { buildProviderSummary } from "../infra/provider-summary.js";
import { triggerWarelayRestart } from "../infra/restart.js";
import { triggerClawdisRestart } from "../infra/restart.js";
import { drainSystemEvents } from "../infra/system-events.js";
import { defaultRuntime } from "../runtime.js";
import { resolveHeartbeatSeconds } from "../web/reconnect.js";
@@ -42,7 +42,7 @@ const ABORT_TRIGGERS = new Set(["stop", "esc", "abort", "wait", "exit"]);
const ABORT_MEMORY = new Map<string, boolean>();
const SYSTEM_MARK = "⚙️";
type ReplyConfig = NonNullable<WarelayConfig["inbound"]>["reply"];
type ReplyConfig = NonNullable<ClawdisConfig["inbound"]>["reply"];
export function extractThinkDirective(body?: string): {
cleaned: string;
@@ -112,7 +112,7 @@ function stripStructuralPrefixes(text: string): string {
function stripMentions(
text: string,
ctx: MsgContext,
cfg: WarelayConfig | undefined,
cfg: ClawdisConfig | undefined,
): string {
let result = text;
const patterns = cfg?.inbound?.groupChat?.mentionPatterns ?? [];
@@ -161,7 +161,7 @@ function makeDefaultPiReply(): ReplyConfig {
export async function getReplyFromConfig(
ctx: MsgContext,
opts?: GetReplyOptions,
configOverride?: WarelayConfig,
configOverride?: ClawdisConfig,
): Promise<ReplyPayload | ReplyPayload[] | undefined> {
// Choose reply from config: static text or external command stdout.
const cfg = configOverride ?? loadConfig();
@@ -503,7 +503,7 @@ export async function getReplyFromConfig(
rawBodyNormalized === "restart" ||
rawBodyNormalized.startsWith("/restart ")
) {
triggerWarelayRestart();
triggerClawdisRestart();
cleanupTyping();
return {
text: "⚙️ Restarting clawdis via launchctl; give me a few seconds to come back online.",

View File

@@ -5,11 +5,11 @@ import path from "node:path";
import { lookupContextTokens } from "../agents/context.js";
import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL } from "../agents/defaults.js";
import type { WarelayConfig } from "../config/config.js";
import type { ClawdisConfig } from "../config/config.js";
import type { SessionEntry, SessionScope } from "../config/sessions.js";
import type { ThinkLevel, VerboseLevel } from "./thinking.js";
type ReplyConfig = NonNullable<WarelayConfig["inbound"]>["reply"];
type ReplyConfig = NonNullable<ClawdisConfig["inbound"]>["reply"];
type StatusArgs = {
reply: ReplyConfig;

View File

@@ -3,7 +3,7 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import type { WarelayConfig } from "../config/config.js";
import type { ClawdisConfig } from "../config/config.js";
import { isVerbose, logVerbose } from "../globals.js";
import { runExec } from "../process/exec.js";
import type { RuntimeEnv } from "../runtime.js";
@@ -14,7 +14,7 @@ export function isAudio(mediaType?: string | null) {
}
export async function transcribeInboundAudio(
cfg: WarelayConfig,
cfg: ClawdisConfig,
ctx: MsgContext,
runtime: RuntimeEnv,
): Promise<{ text: string } | undefined> {

View File

@@ -279,7 +279,7 @@ Examples:
});
program
.command("gateway")
.description("Run the WebSocket Gateway (replaces relay)")
.description("Run the WebSocket Gateway")
.option("--port <port>", "Port for the gateway WebSocket", "18789")
.option(
"--token <token>",

View File

@@ -11,7 +11,7 @@ import {
vi,
} from "vitest";
import * as commandReply from "../auto-reply/command-reply.js";
import type { WarelayConfig } from "../config/config.js";
import type { ClawdisConfig } from "../config/config.js";
import * as configModule from "../config/config.js";
import type { RuntimeEnv } from "../runtime.js";
import { agentCommand } from "./agent.js";
@@ -36,7 +36,7 @@ function makeStorePath() {
function mockConfig(
storePath: string,
replyOverrides?: Partial<NonNullable<WarelayConfig["inbound"]>["reply"]>,
replyOverrides?: Partial<NonNullable<ClawdisConfig["inbound"]>["reply"]>,
) {
configSpy.mockReturnValue({
inbound: {

View File

@@ -12,7 +12,7 @@ import {
type VerboseLevel,
} from "../auto-reply/thinking.js";
import { type CliDeps, createDefaultDeps } from "../cli/deps.js";
import { loadConfig, type WarelayConfig } from "../config/config.js";
import { loadConfig, type ClawdisConfig } from "../config/config.js";
import {
DEFAULT_IDLE_MINUTES,
loadSessionStore,
@@ -50,7 +50,7 @@ type SessionResolution = {
persistedVerbose?: VerboseLevel;
};
function assertCommandConfig(cfg: WarelayConfig) {
function assertCommandConfig(cfg: ClawdisConfig) {
const reply = cfg.inbound?.reply;
if (!reply || reply.mode !== "command" || !reply.command?.length) {
throw new Error(
@@ -58,14 +58,14 @@ function assertCommandConfig(cfg: WarelayConfig) {
);
}
return reply as NonNullable<
NonNullable<WarelayConfig["inbound"]>["reply"]
NonNullable<ClawdisConfig["inbound"]>["reply"]
> & { mode: "command"; command: string[] };
}
function resolveSession(opts: {
to?: string;
sessionId?: string;
replyCfg: NonNullable<NonNullable<WarelayConfig["inbound"]>["reply"]>;
replyCfg: NonNullable<NonNullable<ClawdisConfig["inbound"]>["reply"]>;
}): SessionResolution {
const sessionCfg = opts.replyCfg?.session;
const scope = sessionCfg?.scope ?? "per-sender";

View File

@@ -53,12 +53,12 @@ export async function sendCommand(
return;
}
// Try to send via IPC to running relay first (avoids Signal session corruption)
// Try to send via IPC to running gateway first (avoids Signal session corruption)
const ipcResult = await sendViaIpc(opts.to, opts.message, opts.media);
if (ipcResult) {
if (ipcResult.success) {
runtime.log(
success(`✅ Sent via relay IPC. Message ID: ${ipcResult.messageId}`),
success(`✅ Sent via gateway IPC. Message ID: ${ipcResult.messageId}`),
);
if (opts.json) {
runtime.log(
@@ -77,7 +77,7 @@ export async function sendCommand(
}
return;
}
// IPC failed but relay is running - warn and fall back
// IPC failed but gateway is running - warn and fall back
runtime.log(
info(
`IPC send failed (${ipcResult.error}), falling back to direct connection`,

View File

@@ -66,7 +66,7 @@ export type GroupChatConfig = {
historyLimit?: number;
};
export type WarelayConfig = {
export type ClawdisConfig = {
logging?: LoggingConfig;
inbound?: {
allowFrom?: string[]; // E.164 numbers allowed to trigger auto-reply (without whatsapp:)
@@ -179,7 +179,7 @@ const ReplySchema = z
},
);
const WarelaySchema = z.object({
const ClawdisSchema = z.object({
logging: z
.object({
level: z
@@ -252,7 +252,7 @@ const WarelaySchema = z.object({
.optional(),
});
export function loadConfig(): WarelayConfig {
export function loadConfig(): ClawdisConfig {
// Read config file (JSON5) if present.
const configPath = CONFIG_PATH_CLAWDIS;
try {
@@ -260,7 +260,7 @@ export function loadConfig(): WarelayConfig {
const raw = fs.readFileSync(configPath, "utf-8");
const parsed = JSON5.parse(raw);
if (typeof parsed !== "object" || parsed === null) return {};
const validated = WarelaySchema.safeParse(parsed);
const validated = ClawdisSchema.safeParse(parsed);
if (!validated.success) {
console.error("Invalid config:");
for (const iss of validated.error.issues) {
@@ -268,7 +268,7 @@ export function loadConfig(): WarelayConfig {
}
return {};
}
return validated.data as WarelayConfig;
return validated.data as ClawdisConfig;
} catch (err) {
console.error(`Failed to read config at ${configPath}`, err);
return {};

View File

@@ -1,5 +1,5 @@
import chalk from "chalk";
import { loadConfig, type WarelayConfig } from "../config/config.js";
import { loadConfig, type ClawdisConfig } from "../config/config.js";
import { normalizeE164 } from "../utils.js";
import {
getWebAuthAgeMs,
@@ -10,7 +10,7 @@ import {
const DEFAULT_WEBCHAT_PORT = 18788;
export async function buildProviderSummary(
cfg?: WarelayConfig,
cfg?: ClawdisConfig,
): Promise<string[]> {
const effective = cfg ?? loadConfig();
const lines: string[] = [];

View File

@@ -1,34 +0,0 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { acquireRelayLock, RelayLockError } from "./relay-lock.js";
const newLockPath = () =>
path.join(
os.tmpdir(),
`clawdis-relay-lock-test-${process.pid}-${Math.random().toString(16).slice(2)}.sock`,
);
describe("relay-lock", () => {
it("prevents concurrent relay instances and releases cleanly", async () => {
const lockPath = newLockPath();
const release1 = await acquireRelayLock(lockPath);
expect(fs.existsSync(lockPath)).toBe(true);
await expect(acquireRelayLock(lockPath)).rejects.toBeInstanceOf(
RelayLockError,
);
await release1();
expect(fs.existsSync(lockPath)).toBe(false);
// After release, lock can be reacquired.
const release2 = await acquireRelayLock(lockPath);
await release2();
expect(fs.existsSync(lockPath)).toBe(false);
});
});

View File

@@ -1,102 +0,0 @@
import fs from "node:fs";
import net from "node:net";
import os from "node:os";
import path from "node:path";
const DEFAULT_LOCK_PATH = path.join(os.tmpdir(), "clawdis-relay.lock");
export class RelayLockError extends Error {}
type ReleaseFn = () => Promise<void>;
/**
* Acquire an exclusive single-instance lock for the relay using a Unix domain socket.
*
* Why a socket? If the process crashes or is SIGKILLed, the socket file remains but
* the next start will detect ECONNREFUSED when connecting and clean the stale path
* before retrying. This keeps the lock self-healing without manual pidfile cleanup.
*/
export async function acquireRelayLock(
lockPath = DEFAULT_LOCK_PATH,
): Promise<ReleaseFn> {
// Fast path: try to listen on the lock path.
const attemptListen = (): Promise<net.Server> =>
new Promise((resolve, reject) => {
const server = net.createServer();
server.once("error", async (err: NodeJS.ErrnoException) => {
if (err.code !== "EADDRINUSE") {
reject(new RelayLockError(`lock listen failed: ${err.message}`));
return;
}
// Something is already bound. Try to connect to see if it is alive.
const client = net.connect({ path: lockPath });
client.once("connect", () => {
client.destroy();
reject(
new RelayLockError("another relay instance is already running"),
);
});
client.once("error", (connErr: NodeJS.ErrnoException) => {
// Nothing is listening -> stale socket file. Remove and retry once.
if (connErr.code === "ECONNREFUSED" || connErr.code === "ENOENT") {
try {
fs.rmSync(lockPath, { force: true });
} catch (rmErr) {
reject(
new RelayLockError(
`failed to clean stale lock at ${lockPath}: ${String(rmErr)}`,
),
);
return;
}
attemptListen().then(resolve, reject);
return;
}
reject(
new RelayLockError(
`failed to connect to existing lock (${lockPath}): ${connErr.message}`,
),
);
});
});
server.listen(lockPath, () => resolve(server));
});
const server = await attemptListen();
let released = false;
const release = async (): Promise<void> => {
if (released) return;
released = true;
await new Promise<void>((resolve) => server.close(() => resolve()));
try {
fs.rmSync(lockPath, { force: true });
} catch {
/* ignore */
}
};
const cleanupSignals: NodeJS.Signals[] = ["SIGINT", "SIGTERM", "SIGHUP"];
const handleSignal = async () => {
await release();
process.exit(0);
};
for (const sig of cleanupSignals) {
process.once(sig, () => {
void handleSignal();
});
}
process.once("exit", () => {
// Exit handler must be sync-safe; release is async but close+rm are fast.
void release();
});
return release;
}

View File

@@ -2,9 +2,8 @@ import { spawn } from "node:child_process";
const DEFAULT_LAUNCHD_LABEL = "com.steipete.clawdis";
export function triggerWarelayRestart(): void {
export function triggerClawdisRestart(): void {
const label =
process.env.WARELAY_LAUNCHD_LABEL ||
process.env.CLAWDIS_LAUNCHD_LABEL ||
DEFAULT_LAUNCHD_LABEL;
const uid =

View File

@@ -56,7 +56,7 @@ function initSelfPresence() {
function ensureSelfPresence() {
// If the map was somehow cleared (e.g., hot reload or a new worker spawn that
// skipped module evaluation), re-seed with a local entry so UIs always show
// at least the current relay.
// at least the current gateway.
if (entries.size === 0) {
initSelfPresence();
}

View File

@@ -150,7 +150,7 @@ export async function ensureFunnel(
);
runtime.error(
info(
"Tip: Funnel is optional for CLAWDIS. You can keep running the web relay without it: `pnpm clawdis gateway`",
"Tip: Funnel is optional for CLAWDIS. You can keep running the web gateway without it: `pnpm clawdis gateway`",
),
);
if (isVerbose()) {

View File

@@ -3,7 +3,7 @@ import path from "node:path";
import util from "node:util";
import { Logger as TsLogger } from "tslog";
import { loadConfig, type WarelayConfig } from "./config/config.js";
import { loadConfig, type ClawdisConfig } from "./config/config.js";
import { isVerbose } from "./globals.js";
// Pin to /tmp so mac Debug UI and docs match; os.tmpdir() can be a per-user
@@ -55,7 +55,7 @@ function normalizeLevel(level?: string): Level {
}
function resolveSettings(): ResolvedSettings {
const cfg: WarelayConfig["logging"] | undefined =
const cfg: ClawdisConfig["logging"] | undefined =
overrideSettings ?? loadConfig().logging;
const level = normalizeLevel(cfg?.level);
const file = cfg?.file ?? defaultRollingPathForToday();

View File

@@ -131,7 +131,7 @@ class TauRpcClient {
if (!ok) child.stdin.once("drain", () => resolve());
});
return await new Promise<TauRpcResult>((resolve, reject) => {
// Hard cap to avoid stuck relays; resets on every line received.
// Hard cap to avoid stuck gateways; resets on every line received.
const capMs = Math.min(timeoutMs, 5 * 60 * 1000);
const timer = setTimeout(() => {
this.pending = undefined;

View File

@@ -20,7 +20,7 @@ export async function monitorTelegramProvider(opts: MonitorTelegramOpts = {}) {
const token = (opts.token ?? process.env.TELEGRAM_BOT_TOKEN)?.trim();
if (!token) {
throw new Error(
"TELEGRAM_BOT_TOKEN or telegram.botToken is required for Telegram relay",
"TELEGRAM_BOT_TOKEN or telegram.botToken is required for Telegram gateway",
);
}

View File

@@ -6,7 +6,7 @@ import path from "node:path";
import sharp from "sharp";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { WarelayConfig } from "../config/config.js";
import type { ClawdisConfig } from "../config/config.js";
import { resetLogger, setLoggerOverride } from "../logging.js";
import * as commandQueue from "../process/command-queue.js";
import {
@@ -65,7 +65,7 @@ describe("heartbeat helpers", () => {
});
it("resolves heartbeat minutes with default and overrides", () => {
const cfgBase: WarelayConfig = {
const cfgBase: ClawdisConfig = {
inbound: {
reply: { mode: "command" as const },
},
@@ -94,7 +94,7 @@ describe("resolveHeartbeatRecipients", () => {
it("returns the sole session recipient", async () => {
const now = Date.now();
const store = await makeSessionStore({ "+1000": { updatedAt: now } });
const cfg: WarelayConfig = {
const cfg: ClawdisConfig = {
inbound: {
allowFrom: ["+1999"],
reply: { mode: "command", session: { store: store.storePath } },
@@ -112,7 +112,7 @@ describe("resolveHeartbeatRecipients", () => {
"+1000": { updatedAt: now },
"+2000": { updatedAt: now - 10 },
});
const cfg: WarelayConfig = {
const cfg: ClawdisConfig = {
inbound: {
allowFrom: ["+1999"],
reply: { mode: "command", session: { store: store.storePath } },
@@ -126,7 +126,7 @@ describe("resolveHeartbeatRecipients", () => {
it("filters wildcard allowFrom when no sessions exist", async () => {
const store = await makeSessionStore({});
const cfg: WarelayConfig = {
const cfg: ClawdisConfig = {
inbound: {
allowFrom: ["*"],
reply: { mode: "command", session: { store: store.storePath } },
@@ -141,7 +141,7 @@ describe("resolveHeartbeatRecipients", () => {
it("merges sessions and allowFrom when --all is set", async () => {
const now = Date.now();
const store = await makeSessionStore({ "+1000": { updatedAt: now } });
const cfg: WarelayConfig = {
const cfg: ClawdisConfig = {
inbound: {
allowFrom: ["+1999"],
reply: { mode: "command", session: { store: store.storePath } },
@@ -162,7 +162,7 @@ describe("partial reply gating", () => {
const replyResolver = vi.fn().mockResolvedValue({ text: "final reply" });
const mockConfig: WarelayConfig = {
const mockConfig: ClawdisConfig = {
inbound: {
reply: { mode: "command" },
allowFrom: ["*"],
@@ -342,7 +342,7 @@ describe("runWebHeartbeatOnce", () => {
const replyResolver = vi.fn().mockResolvedValue({ text: HEARTBEAT_TOKEN });
const runtime = { log: vi.fn(), error: vi.fn(), exit: vi.fn() } as never;
const cfg: WarelayConfig = {
const cfg: ClawdisConfig = {
inbound: {
allowFrom: ["+4367"],
reply: {
@@ -385,7 +385,7 @@ describe("runWebHeartbeatOnce", () => {
}));
const resolver = vi.fn(async () => ({ text: HEARTBEAT_TOKEN }));
const cfg: WarelayConfig = {
const cfg: ClawdisConfig = {
inbound: {
allowFrom: ["+1999"],
reply: {

View File

@@ -41,7 +41,7 @@ export function setHeartbeatsEnabled(enabled: boolean) {
}
/**
* Send a message via IPC if relay is running, otherwise fall back to direct.
* Send a message via IPC if gateway is running, otherwise fall back to direct.
* This avoids Signal session corruption from multiple Baileys connections.
*/
async function sendWithIpcFallback(
@@ -52,7 +52,7 @@ async function sendWithIpcFallback(
const ipcResult = await sendViaIpc(to, message, opts.mediaUrl);
if (ipcResult?.success && ipcResult.messageId) {
if (opts.verbose) {
console.log(info(`Sent via relay IPC (avoiding session corruption)`));
console.log(info(`Sent via gateway IPC (avoiding session corruption)`));
}
return { messageId: ipcResult.messageId, toJid: `${to}@s.whatsapp.net` };
}
@@ -720,7 +720,7 @@ export async function monitorWebProvider(
);
// Avoid noisy MaxListenersExceeded warnings in test environments where
// multiple relay instances may be constructed.
// multiple gateway instances may be constructed.
const currentMaxListeners = process.getMaxListeners?.() ?? 10;
if (process.setMaxListeners && currentMaxListeners < 50) {
process.setMaxListeners(50);
@@ -1021,7 +1021,7 @@ export async function monitorWebProvider(
// Surface a concise connection event for the next main-session turn/heartbeat.
const { e164: selfE164 } = readWebSelfId();
enqueueSystemEvent(
`WhatsApp relay connected${selfE164 ? ` as ${selfE164}` : ""}.`,
`WhatsApp gateway connected${selfE164 ? ` as ${selfE164}` : ""}.`,
);
// Start IPC server so `clawdis send` can use this connection
@@ -1099,10 +1099,10 @@ export async function monitorWebProvider(
if (minutesSinceLastMessage && minutesSinceLastMessage > 30) {
heartbeatLogger.warn(
logData,
"⚠️ web relay heartbeat - no messages in 30+ minutes",
"⚠️ web gateway heartbeat - no messages in 30+ minutes",
);
} else {
heartbeatLogger.info(logData, "web relay heartbeat");
heartbeatLogger.info(logData, "web gateway heartbeat");
}
}, heartbeatSeconds * 1000);
@@ -1398,7 +1398,7 @@ export async function monitorWebProvider(
);
enqueueSystemEvent(
`WhatsApp relay disconnected (status ${status ?? "unknown"})`,
`WhatsApp gateway disconnected (status ${status ?? "unknown"})`,
);
if (loggedOut) {

View File

@@ -64,7 +64,7 @@ export async function monitorWebInbox(options: {
onCloseResolve = resolve;
});
try {
// Advertise that the relay is online right after connecting.
// Advertise that the gateway is online right after connecting.
await sock.sendPresenceUpdate("available");
if (isVerbose()) logVerbose("Sent global 'available' presence on connect");
} catch (err) {

View File

@@ -1,7 +1,7 @@
/**
* IPC server for clawdis relay.
* IPC server for clawdis gateway.
*
* When the relay is running, it starts a Unix socket server that allows
* When the gateway is running, it starts a Unix socket server that allows
* `clawdis send` and `clawdis heartbeat` to send messages through the
* existing WhatsApp connection instead of creating new ones.
*
@@ -40,7 +40,7 @@ type SendHandler = (
let server: net.Server | null = null;
/**
* Start the IPC server. Called by the relay when it starts.
* Start the IPC server. Called by the gateway when it starts.
*/
export function startIpcServer(sendHandler: SendHandler): void {
const logger = getChildLogger({ module: "ipc-server" });
@@ -126,7 +126,7 @@ export function startIpcServer(sendHandler: SendHandler): void {
}
/**
* Stop the IPC server. Called when relay shuts down.
* Stop the IPC server. Called when gateway shuts down.
*/
export function stopIpcServer(): void {
if (server) {
@@ -141,7 +141,7 @@ export function stopIpcServer(): void {
}
/**
* Check if the relay IPC server is running.
* Check if the gateway IPC server is running.
*/
export function isRelayRunning(): boolean {
try {
@@ -154,8 +154,8 @@ export function isRelayRunning(): boolean {
}
/**
* Send a message through the running relay's IPC.
* Returns null if relay is not running.
* Send a message through the running gateway's IPC.
* Returns null if gateway is not running.
*/
export async function sendViaIpc(
to: string,
@@ -214,7 +214,7 @@ export async function sendViaIpc(
if (!resolved) {
resolved = true;
clearTimeout(timeout);
// Socket exists but can't connect - relay might have crashed
// Socket exists but can't connect - gateway might have crashed
resolve(null);
}
});

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import type { WarelayConfig } from "../config/config.js";
import type { ClawdisConfig } from "../config/config.js";
import {
computeBackoff,
DEFAULT_HEARTBEAT_SECONDS,
@@ -11,7 +11,7 @@ import {
} from "./reconnect.js";
describe("web reconnect helpers", () => {
const cfg: WarelayConfig = {};
const cfg: ClawdisConfig = {};
it("resolves sane reconnect defaults with clamps", () => {
const policy = resolveReconnectPolicy(cfg, {

View File

@@ -1,6 +1,6 @@
import { randomUUID } from "node:crypto";
import type { WarelayConfig } from "../config/config.js";
import type { ClawdisConfig } from "../config/config.js";
export type ReconnectPolicy = {
initialMs: number;
@@ -23,7 +23,7 @@ const clamp = (val: number, min: number, max: number) =>
Math.max(min, Math.min(max, val));
export function resolveHeartbeatSeconds(
cfg: WarelayConfig,
cfg: ClawdisConfig,
overrideSeconds?: number,
): number {
const candidate = overrideSeconds ?? cfg.web?.heartbeatSeconds;
@@ -32,7 +32,7 @@ export function resolveHeartbeatSeconds(
}
export function resolveReconnectPolicy(
cfg: WarelayConfig,
cfg: ClawdisConfig,
overrides?: Partial<ReconnectPolicy>,
): ReconnectPolicy {
const merged = {