refactor(status): consolidate scan projections and lazy loaders (#119412)

This commit is contained in:
Peter Steinberger
2026-08-04 19:41:40 -07:00
committed by GitHub
parent 722dfb3d64
commit 5ffd2dfbc3
5 changed files with 83 additions and 216 deletions
+3 -18
View File
@@ -77,27 +77,12 @@ export function buildStatusOverviewSurfaceFromScan(
export function buildStatusOverviewSurfaceFromOverview(
params: { overview: StatusOverviewInput } & StatusOverviewServices,
): StatusOverviewSurface {
return {
cfg: params.overview.cfg,
update: params.overview.update,
tailscaleMode: params.overview.tailscaleMode,
tailscaleDns: params.overview.tailscaleDns,
tailscaleHttpsUrl: params.overview.tailscaleHttpsUrl,
...(params.overview.advertisedControlUiLinks
? { advertisedControlUiLinks: params.overview.advertisedControlUiLinks }
: {}),
gatewayMode: params.overview.gatewaySnapshot.gatewayMode,
remoteUrlMissing: params.overview.gatewaySnapshot.remoteUrlMissing,
gatewayConnection: params.overview.gatewaySnapshot.gatewayConnection,
gatewayReachable: params.overview.gatewaySnapshot.gatewayReachable,
gatewayProbe: params.overview.gatewaySnapshot.gatewayProbe,
gatewayProbeAuth: params.overview.gatewaySnapshot.gatewayProbeAuth,
gatewayProbeAuthWarning: params.overview.gatewaySnapshot.gatewayProbeAuthWarning,
gatewaySelf: params.overview.gatewaySnapshot.gatewaySelf,
return buildStatusOverviewSurfaceFromScan({
scan: { ...params.overview, ...params.overview.gatewaySnapshot },
gatewayService: params.gatewayService,
nodeService: params.nodeService,
nodeOnlyGateway: params.nodeOnlyGateway,
};
});
}
/** Builds overview rows from an already-normalized surface. */
+23 -36
View File
@@ -37,26 +37,6 @@ const statusCommandTextRuntimeLoader = createLazyImportLoader(
);
const statusNodeModeModuleLoader = createLazyImportLoader(() => import("./status.node-mode.js"));
function loadStatusScanModule() {
return statusScanModuleLoader.load();
}
function loadStatusScanFastJsonModule() {
return statusScanFastJsonModuleLoader.load();
}
function loadStatusAllModule() {
return statusAllModuleLoader.load();
}
function loadStatusCommandTextRuntime() {
return statusCommandTextRuntimeLoader.load();
}
function loadStatusNodeModeModule() {
return statusNodeModeModuleLoader.load();
}
/** Extracts device-pairing recovery context from structured gateway errors or legacy message text. */
function resolvePairingRecoveryContext(params: {
error?: string | null;
@@ -131,9 +111,9 @@ export async function statusCommand(
) {
if (opts.all && !opts.json) {
// Human `--all` has a dedicated report path; JSON `--all` stays on the JSON schema.
await loadStatusAllModule().then(({ statusAllCommand }) =>
statusAllCommand(runtime, { timeoutMs: opts.timeoutMs }),
);
await statusAllModuleLoader
.load()
.then(({ statusAllCommand }) => statusAllCommand(runtime, { timeoutMs: opts.timeoutMs }));
return;
}
@@ -145,16 +125,21 @@ export async function statusCommand(
includePluginCompatibility: opts.all === true,
suppressHealthErrors: true,
scanStatusJsonFast: async (scanOpts, runtimeForScan) =>
await loadStatusScanFastJsonModule().then(({ scanStatusJsonFast }) =>
scanStatusJsonFast(scanOpts, runtimeForScan),
),
await statusScanFastJsonModuleLoader
.load()
.then(({ scanStatusJsonFast }) => scanStatusJsonFast(scanOpts, runtimeForScan)),
});
return;
}
const scan = await loadStatusScanModule().then(({ scanStatus }) =>
scanStatus({ json: false, timeoutMs: opts.timeoutMs, all: opts.all, deep: opts.deep }, runtime),
);
const scan = await statusScanModuleLoader
.load()
.then(({ scanStatus }) =>
scanStatus(
{ json: false, timeoutMs: opts.timeoutMs, all: opts.all, deep: opts.deep },
runtime,
),
);
const {
cfg,
@@ -250,7 +235,7 @@ export async function statusCommand(
resolveMemoryVectorState,
shortenText,
theme,
} = await loadStatusCommandTextRuntime();
} = await statusCommandTextRuntimeLoader.load();
const muted = (value: string) => (rich ? theme.muted(value) : value);
const ok = (value: string) => (rich ? theme.success(value) : value);
const warn = (value: string) => (rich ? theme.warn(value) : value);
@@ -289,12 +274,14 @@ export async function statusCommand(
runtime.log("");
}
const nodeOnlyGateway = await loadStatusNodeModeModule().then(({ resolveNodeOnlyGatewayInfo }) =>
resolveNodeOnlyGatewayInfo({
daemon,
node: nodeDaemon,
}),
);
const nodeOnlyGateway = await statusNodeModeModuleLoader
.load()
.then(({ resolveNodeOnlyGatewayInfo }) =>
resolveNodeOnlyGatewayInfo({
daemon,
node: nodeDaemon,
}),
);
const pairingRecovery = resolvePairingRecoveryContext({
error: gatewayProbe?.error ?? null,
closeReason: gatewayProbe?.close?.reason ?? null,
+1 -5
View File
@@ -16,10 +16,6 @@ const statusScanDepsRuntimeModuleLoader = createLazyImportLoader(
() => import("./status.scan.deps.runtime.js"),
);
function loadStatusScanDepsRuntimeModule() {
return statusScanDepsRuntimeModuleLoader.load();
}
/** Returns the owning agent database path for built-in memory. */
export function resolveDefaultMemoryDatabasePath(agentId: string): string {
return resolveOpenClawAgentSqlitePath({ agentId });
@@ -32,7 +28,7 @@ export async function resolveStatusMemoryStatusSnapshot(params: {
memoryPlugin: MemoryPluginStatus;
requireDefaultDatabasePath?: (agentId: string) => string;
}): Promise<MemoryStatusSnapshot | null> {
const { getMemorySearchManager } = await loadStatusScanDepsRuntimeModule();
const { getMemorySearchManager } = await statusScanDepsRuntimeModuleLoader.load();
return await resolveSharedMemoryStatusSnapshot({
cfg: params.cfg,
agentStatus: params.agentStatus,
+20 -62
View File
@@ -44,50 +44,6 @@ const commandSecretTargetsModuleLoader = createLazyImportLoader(
() => import("../cli/command-secret-targets.js"),
);
function loadStatusScanDepsRuntimeModule() {
return statusScanDepsRuntimeModuleLoader.load();
}
function loadStatusAgentLocalModule() {
return statusAgentLocalModuleLoader.load();
}
function loadStatusUpdateModule() {
return statusUpdateModuleLoader.load();
}
function loadStatusScanRuntimeModule() {
return statusScanRuntimeModuleLoader.load();
}
function loadGatewayCallModule() {
return gatewayCallModuleLoader.load();
}
function loadStatusSummaryModule() {
return statusSummaryModuleLoader.load();
}
function loadChannelPluginIdsModule() {
return channelPluginIdsModuleLoader.load();
}
function loadConfigModule() {
return configModuleLoader.load();
}
function loadControlUiLinksModule() {
return controlUiLinksModuleLoader.load();
}
function loadCommandConfigResolutionModule() {
return commandConfigResolutionModuleLoader.load();
}
function loadCommandSecretTargetsModule() {
return commandSecretTargetsModuleLoader.load();
}
async function resolveStatusChannelsStatus(params: {
cfg: OpenClawConfig;
gatewayReachable: boolean;
@@ -99,7 +55,7 @@ async function resolveStatusChannelsStatus(params: {
// Avoid a second gateway call after probe failure; channel tables can still summarize local config.
return null;
}
const { callGateway } = await loadGatewayCallModule();
const { callGateway } = await gatewayCallModuleLoader.load();
return await callGateway({
config: params.cfg,
method: "channels.status",
@@ -193,17 +149,17 @@ export async function collectStatusScanOverview(params: {
commandName: params.commandName,
allowMissingConfigFastPath: params.allowMissingConfigFastPath,
readConfigSnapshot: async () =>
(await loadConfigModule()).readBestEffortConfigSnapshot({
(await configModuleLoader.load()).readBestEffortConfigSnapshot({
observe: false,
skipPluginValidation: params.skipConfigPluginValidation,
}),
resolveConfig: async (loadedConfig) =>
await (
await loadCommandConfigResolutionModule()
await commandConfigResolutionModuleLoader.load()
).resolveCommandConfigWithSecrets({
config: loadedConfig,
commandName: params.commandName,
targetIds: (await loadCommandSecretTargetsModule()).getStatusCommandSecretTargetIds(
targetIds: (await commandSecretTargetsModuleLoader.load()).getStatusCommandSecretTargetIds(
loadedConfig,
process.env,
{ includeChannelTargets: params.includeChannelSecretTargets },
@@ -215,7 +171,7 @@ export async function collectStatusScanOverview(params: {
params.progress?.tick();
const hasConfiguredChannels = params.resolveHasConfiguredChannels
? await params.resolveHasConfiguredChannels(cfg, sourceConfig)
: await loadChannelPluginIdsModule().then(({ hasConfiguredChannelsForReadOnlyScope }) =>
: await channelPluginIdsModuleLoader.load().then(({ hasConfiguredChannelsForReadOnlyScope }) =>
hasConfiguredChannelsForReadOnlyScope({
config: cfg,
activationSourceConfig: sourceConfig,
@@ -239,18 +195,18 @@ export async function collectStatusScanOverview(params: {
includeLocalStatusRpcFallback: params.includeLocalStatusRpcFallback,
gatewayProbeTimeoutMs,
getTailnetHostname: async (runner) => {
return await loadStatusScanDepsRuntimeModule().then(({ getTailnetHostname }) =>
getTailnetHostname(runner),
);
return await statusScanDepsRuntimeModuleLoader
.load()
.then(({ getTailnetHostname }) => getTailnetHostname(runner));
},
getUpdateCheckResult: async (updateParams) =>
await loadStatusUpdateModule().then(({ getUpdateCheckResult }) =>
getUpdateCheckResult(updateParams),
),
await statusUpdateModuleLoader
.load()
.then(({ getUpdateCheckResult }) => getUpdateCheckResult(updateParams)),
getAgentLocalStatuses: async (bootstrapCfg) =>
await loadStatusAgentLocalModule().then(({ getAgentLocalStatuses }) =>
getAgentLocalStatuses(bootstrapCfg),
),
await statusAgentLocalModuleLoader
.load()
.then(({ getAgentLocalStatuses }) => getAgentLocalStatuses(bootstrapCfg)),
});
if (params.labels?.checkingTailscale) {
@@ -280,9 +236,9 @@ export async function collectStatusScanOverview(params: {
const tailscaleHttpsUrl = await bootstrap.resolveTailscaleHttpsUrl();
const advertisedControlUiLinks =
params.includeAdvertisedControlUiLinks === true && cfg.gateway?.controlUi?.enabled !== false
? await loadControlUiLinksModule().then(async ({ resolveAdvertisedControlUiLinks }) =>
? await controlUiLinksModuleLoader.load().then(async ({ resolveAdvertisedControlUiLinks }) =>
resolveAdvertisedControlUiLinks({
port: (await loadConfigModule()).resolveGatewayPort(cfg),
port: (await configModuleLoader.load()).resolveGatewayPort(cfg),
bind: cfg.gateway?.bind,
customBindHost: cfg.gateway?.customBindHost,
basePath: cfg.gateway?.controlUi?.basePath,
@@ -309,7 +265,9 @@ export async function collectStatusScanOverview(params: {
params.progress?.tick();
// Runtime channel helpers stay lazy because JSON fast paths can skip channel data entirely.
const { collectChannelStatusIssues, buildChannelsTable } =
await loadStatusScanRuntimeModule().then(({ statusScanRuntime }) => statusScanRuntime);
await statusScanRuntimeModuleLoader
.load()
.then(({ statusScanRuntime }) => statusScanRuntime);
const channelIssuesLocal = channelsStatusLocal
? collectChannelStatusIssues(channelsStatusLocal)
: [];
@@ -367,7 +325,7 @@ export async function resolveStatusSummaryFromOverview(params: {
if (params.overview.skipColdStartNetworkChecks) {
return buildColdStartStatusSummary();
}
return await loadStatusSummaryModule().then(({ getStatusSummary }) =>
return await statusSummaryModuleLoader.load().then(({ getStatusSummary }) =>
getStatusSummary({
config: params.overview.cfg,
sourceConfig: params.overview.sourceConfig,
+36 -95
View File
@@ -1,107 +1,48 @@
// Normalized full status scan result shape.
// Builders flatten the gateway snapshot so downstream text/JSON code reads one stable object.
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { collectChannelStatusIssues as collectChannelStatusIssuesFn } from "../infra/channels-status-issues.js";
import { resolveOsSummary } from "../infra/os-summary.js";
import type { UpdateCheckResult } from "../infra/update-check.js";
import type { PluginCompatibilityNotice } from "../plugins/status.js";
import type { getStatusSummary as getStatusSummaryFn } from "../status/summary.js";
import type { pickGatewaySelfPresence } from "./gateway-presence.js";
import type { buildChannelsTable as buildChannelsTableFn } from "./status-all/channels.js";
import type { getAgentLocalStatuses as getAgentLocalStatusesFn } from "./status.agent-local.js";
import type {
GatewayProbeSnapshot,
MemoryPluginStatus,
MemoryStatusSnapshot,
} from "./status.scan.shared.js";
import type { StatusScanOverviewResult } from "./status.scan-overview.ts";
import type { MemoryPluginStatus, MemoryStatusSnapshot } from "./status.scan.shared.js";
export type StatusScanResult = {
cfg: OpenClawConfig;
sourceConfig: OpenClawConfig;
secretDiagnostics: string[];
osSummary: ReturnType<typeof resolveOsSummary>;
tailscaleMode: string;
tailscaleDns: string | null;
tailscaleHttpsUrl: string | null;
advertisedControlUiLinks?: { httpUrl: string; wsUrl: string };
update: UpdateCheckResult;
gatewayConnection: GatewayProbeSnapshot["gatewayConnection"];
remoteUrlMissing: boolean;
gatewayMode: "local" | "remote";
gatewayProbeAuth: {
token?: string;
password?: string;
type StatusScanGatewayResult = Omit<
StatusScanOverviewResult["gatewaySnapshot"],
"gatewayCallOverrides"
>;
export type StatusScanResult = Omit<
StatusScanOverviewResult,
| "coldStart"
| "hasConfiguredChannels"
| "skipColdStartNetworkChecks"
| "gatewaySnapshot"
| "channelsStatus"
> &
StatusScanGatewayResult & {
summary: Awaited<ReturnType<typeof getStatusSummaryFn>>;
memory: MemoryStatusSnapshot | null;
memoryPlugin: MemoryPluginStatus;
pluginCompatibility: PluginCompatibilityNotice[];
};
gatewayProbeAuthWarning?: string;
gatewayProbe: GatewayProbeSnapshot["gatewayProbe"];
gatewayReachable: boolean;
gatewaySelf: ReturnType<typeof pickGatewaySelfPresence>;
channelIssues: ReturnType<typeof collectChannelStatusIssuesFn>;
agentStatus: Awaited<ReturnType<typeof getAgentLocalStatusesFn>>;
channels: Awaited<ReturnType<typeof buildChannelsTableFn>>;
summary: Awaited<ReturnType<typeof getStatusSummaryFn>>;
memory: MemoryStatusSnapshot | null;
memoryPlugin: MemoryPluginStatus;
pluginCompatibility: PluginCompatibilityNotice[];
};
/** Flattens overview, gateway, channel, summary, memory, and compatibility inputs into a scan result. */
export function buildStatusScanResult(params: {
cfg: OpenClawConfig;
sourceConfig: OpenClawConfig;
secretDiagnostics: string[];
osSummary: ReturnType<typeof resolveOsSummary>;
tailscaleMode: string;
tailscaleDns: string | null;
tailscaleHttpsUrl: string | null;
advertisedControlUiLinks?: { httpUrl: string; wsUrl: string };
update: UpdateCheckResult;
gatewaySnapshot: Pick<
GatewayProbeSnapshot,
| "gatewayConnection"
| "remoteUrlMissing"
| "gatewayMode"
| "gatewayProbeAuth"
| "gatewayProbeAuthWarning"
| "gatewayProbe"
| "gatewayReachable"
| "gatewaySelf"
>;
channelIssues: ReturnType<typeof collectChannelStatusIssuesFn>;
agentStatus: Awaited<ReturnType<typeof getAgentLocalStatusesFn>>;
channels: Awaited<ReturnType<typeof buildChannelsTableFn>>;
summary: Awaited<ReturnType<typeof getStatusSummaryFn>>;
memory: MemoryStatusSnapshot | null;
memoryPlugin: MemoryPluginStatus;
pluginCompatibility: PluginCompatibilityNotice[];
}): StatusScanResult {
export function buildStatusScanResult(
params: Omit<StatusScanResult, keyof StatusScanGatewayResult> & {
gatewaySnapshot: StatusScanGatewayResult;
},
): StatusScanResult {
const { gatewaySnapshot, advertisedControlUiLinks, ...result } = params;
return {
cfg: params.cfg,
sourceConfig: params.sourceConfig,
secretDiagnostics: params.secretDiagnostics,
osSummary: params.osSummary,
tailscaleMode: params.tailscaleMode,
tailscaleDns: params.tailscaleDns,
tailscaleHttpsUrl: params.tailscaleHttpsUrl,
...(params.advertisedControlUiLinks
? { advertisedControlUiLinks: params.advertisedControlUiLinks }
: {}),
update: params.update,
gatewayConnection: params.gatewaySnapshot.gatewayConnection,
remoteUrlMissing: params.gatewaySnapshot.remoteUrlMissing,
gatewayMode: params.gatewaySnapshot.gatewayMode,
gatewayProbeAuth: params.gatewaySnapshot.gatewayProbeAuth,
gatewayProbeAuthWarning: params.gatewaySnapshot.gatewayProbeAuthWarning,
gatewayProbe: params.gatewaySnapshot.gatewayProbe,
gatewayReachable: params.gatewaySnapshot.gatewayReachable,
gatewaySelf: params.gatewaySnapshot.gatewaySelf,
channelIssues: params.channelIssues,
agentStatus: params.agentStatus,
channels: params.channels,
summary: params.summary,
memory: params.memory,
memoryPlugin: params.memoryPlugin,
pluginCompatibility: params.pluginCompatibility,
...result,
...(advertisedControlUiLinks ? { advertisedControlUiLinks } : {}),
gatewayConnection: gatewaySnapshot.gatewayConnection,
remoteUrlMissing: gatewaySnapshot.remoteUrlMissing,
gatewayMode: gatewaySnapshot.gatewayMode,
gatewayProbeAuth: gatewaySnapshot.gatewayProbeAuth,
gatewayProbeAuthWarning: gatewaySnapshot.gatewayProbeAuthWarning,
gatewayProbe: gatewaySnapshot.gatewayProbe,
gatewayReachable: gatewaySnapshot.gatewayReachable,
gatewaySelf: gatewaySnapshot.gatewaySelf,
};
}