import type { OpenClawConfig } from "../config/types.js"; import type { HeartbeatEventPayload } from "../infra/heartbeat-events.js"; import type { HealthSummary } from "./health.js"; import { getDaemonStatusSummary, getNodeDaemonStatusSummary } from "./status.daemon.js"; let providerUsagePromise: Promise | undefined; let securityAuditModulePromise: Promise | undefined; let gatewayCallModulePromise: Promise | undefined; function loadProviderUsage() { providerUsagePromise ??= import("../infra/provider-usage.js"); return providerUsagePromise; } function loadSecurityAuditModule() { securityAuditModulePromise ??= import("../security/audit.runtime.js"); return securityAuditModulePromise; } function loadGatewayCallModule() { gatewayCallModulePromise ??= import("../gateway/call.js"); return gatewayCallModulePromise; } export async function resolveStatusSecurityAudit(params: { config: OpenClawConfig; sourceConfig: OpenClawConfig; }) { const { runSecurityAudit } = await loadSecurityAuditModule(); return await runSecurityAudit({ config: params.config, sourceConfig: params.sourceConfig, deep: false, includeFilesystem: true, includeChannelSecurity: true, }); } export async function resolveStatusUsageSummary(timeoutMs?: number) { const { loadProviderUsageSummary } = await loadProviderUsage(); return await loadProviderUsageSummary({ timeoutMs }); } export async function loadStatusProviderUsageModule() { return await loadProviderUsage(); } export async function resolveStatusGatewayHealth(params: { config: OpenClawConfig; timeoutMs?: number; }) { const { callGateway } = await loadGatewayCallModule(); return await callGateway({ method: "health", params: { probe: true }, timeoutMs: params.timeoutMs, config: params.config, }); } export async function resolveStatusGatewayHealthSafe(params: { config: OpenClawConfig; timeoutMs?: number; gatewayReachable: boolean; gatewayProbeError?: string | null; callOverrides?: { url: string; token?: string; password?: string; }; }) { if (!params.gatewayReachable) { return { error: params.gatewayProbeError ?? "gateway unreachable" }; } const { callGateway } = await loadGatewayCallModule(); return await callGateway({ method: "health", params: { probe: true }, timeoutMs: params.timeoutMs, config: params.config, ...params.callOverrides, }).catch((err) => ({ error: String(err) })); } export async function resolveStatusLastHeartbeat(params: { config: OpenClawConfig; timeoutMs?: number; gatewayReachable: boolean; }) { if (!params.gatewayReachable) { return null; } const { callGateway } = await loadGatewayCallModule(); return await callGateway({ method: "last-heartbeat", params: {}, timeoutMs: params.timeoutMs, config: params.config, }).catch(() => null); } export async function resolveStatusServiceSummaries() { return await Promise.all([getDaemonStatusSummary(), getNodeDaemonStatusSummary()]); } type StatusUsageSummary = Awaited>; type StatusGatewayHealth = Awaited>; type StatusLastHeartbeat = Awaited>; type StatusGatewayServiceSummary = Awaited>; type StatusNodeServiceSummary = Awaited>; type StatusSecurityAudit = Awaited>; export async function resolveStatusRuntimeDetails(params: { config: OpenClawConfig; timeoutMs?: number; usage?: boolean; deep?: boolean; gatewayReachable: boolean; suppressHealthErrors?: boolean; resolveUsage?: (timeoutMs?: number) => Promise; resolveHealth?: (input: { config: OpenClawConfig; timeoutMs?: number; }) => Promise; }) { const resolveUsageSummary = params.resolveUsage ?? resolveStatusUsageSummary; const resolveGatewayHealthSummary = params.resolveHealth ?? resolveStatusGatewayHealth; const usage = params.usage ? await resolveUsageSummary(params.timeoutMs) : undefined; const health = params.deep ? params.suppressHealthErrors ? await resolveGatewayHealthSummary({ config: params.config, timeoutMs: params.timeoutMs, }).catch(() => undefined) : await resolveGatewayHealthSummary({ config: params.config, timeoutMs: params.timeoutMs, }) : undefined; const lastHeartbeat = params.deep ? await resolveStatusLastHeartbeat({ config: params.config, timeoutMs: params.timeoutMs, gatewayReachable: params.gatewayReachable, }) : null; const [gatewayService, nodeService] = await resolveStatusServiceSummaries(); const result = { usage, health, lastHeartbeat, gatewayService, nodeService, }; return result satisfies { usage?: StatusUsageSummary; health?: StatusGatewayHealth; lastHeartbeat: StatusLastHeartbeat; gatewayService: StatusGatewayServiceSummary; nodeService: StatusNodeServiceSummary; }; } export async function resolveStatusRuntimeSnapshot(params: { config: OpenClawConfig; sourceConfig: OpenClawConfig; timeoutMs?: number; usage?: boolean; deep?: boolean; gatewayReachable: boolean; includeSecurityAudit?: boolean; suppressHealthErrors?: boolean; resolveSecurityAudit?: (input: { config: OpenClawConfig; sourceConfig: OpenClawConfig; }) => Promise; resolveUsage?: (timeoutMs?: number) => Promise; resolveHealth?: (input: { config: OpenClawConfig; timeoutMs?: number; }) => Promise; }) { const securityAudit = params.includeSecurityAudit ? await (params.resolveSecurityAudit ?? resolveStatusSecurityAudit)({ config: params.config, sourceConfig: params.sourceConfig, }) : undefined; const runtimeDetails = await resolveStatusRuntimeDetails({ config: params.config, timeoutMs: params.timeoutMs, usage: params.usage, deep: params.deep, gatewayReachable: params.gatewayReachable, suppressHealthErrors: params.suppressHealthErrors, resolveUsage: params.resolveUsage, resolveHealth: params.resolveHealth, }); return { securityAudit, ...runtimeDetails, } satisfies { securityAudit?: StatusSecurityAudit; usage?: StatusUsageSummary; health?: StatusGatewayHealth; lastHeartbeat: StatusLastHeartbeat; gatewayService: StatusGatewayServiceSummary; nodeService: StatusNodeServiceSummary; }; }