Files
clawdbot/src/gateway/server/health-state.ts
2026-01-15 08:05:41 +00:00

79 lines
2.5 KiB
TypeScript

import { resolveDefaultAgentId } from "../../agents/agent-scope.js";
import { getHealthSnapshot, type HealthSummary } from "../../commands/health.js";
import { CONFIG_PATH_CLAWDBOT, STATE_DIR_CLAWDBOT, loadConfig } from "../../config/config.js";
import { resolveMainSessionKey } from "../../config/sessions.js";
import { normalizeMainKey } from "../../routing/session-key.js";
import { listSystemPresence } from "../../infra/system-presence.js";
import type { Snapshot } from "../protocol/index.js";
let presenceVersion = 1;
let healthVersion = 1;
let healthCache: HealthSummary | null = null;
let healthRefresh: Promise<HealthSummary> | null = null;
let broadcastHealthUpdate: ((snap: HealthSummary) => void) | null = null;
export function buildGatewaySnapshot(): Snapshot {
const cfg = loadConfig();
const defaultAgentId = resolveDefaultAgentId(cfg);
const mainKey = normalizeMainKey(cfg.session?.mainKey);
const mainSessionKey = resolveMainSessionKey(cfg);
const scope = cfg.session?.scope ?? "per-sender";
const presence = listSystemPresence();
const uptimeMs = Math.round(process.uptime() * 1000);
// Health is async; caller should await getHealthSnapshot and replace later if needed.
const emptyHealth: unknown = {};
return {
presence,
health: emptyHealth,
stateVersion: { presence: presenceVersion, health: healthVersion },
uptimeMs,
// Surface resolved paths so UIs can display the true config location.
configPath: CONFIG_PATH_CLAWDBOT,
stateDir: STATE_DIR_CLAWDBOT,
sessionDefaults: {
defaultAgentId,
mainKey,
mainSessionKey,
scope,
},
};
}
export function getHealthCache(): HealthSummary | null {
return healthCache;
}
export function getHealthVersion(): number {
return healthVersion;
}
export function incrementPresenceVersion(): number {
presenceVersion += 1;
return presenceVersion;
}
export function getPresenceVersion(): number {
return presenceVersion;
}
export function setBroadcastHealthUpdate(fn: ((snap: HealthSummary) => void) | null) {
broadcastHealthUpdate = fn;
}
export async function refreshGatewayHealthSnapshot(opts?: { probe?: boolean }) {
if (!healthRefresh) {
healthRefresh = (async () => {
const snap = await getHealthSnapshot({ probe: opts?.probe });
healthCache = snap;
healthVersion += 1;
if (broadcastHealthUpdate) {
broadcastHealthUpdate(snap);
}
return snap;
})().finally(() => {
healthRefresh = null;
});
}
return healthRefresh;
}