style: format health/status files
This commit is contained in:
@@ -13,10 +13,7 @@ import {
|
||||
resolveHeartbeatSummaryForAgent,
|
||||
} from "../infra/heartbeat-runner.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import {
|
||||
buildChannelAccountBindings,
|
||||
resolvePreferredAccountId,
|
||||
} from "../routing/bindings.js";
|
||||
import { buildChannelAccountBindings, resolvePreferredAccountId } from "../routing/bindings.js";
|
||||
import { normalizeAgentId } from "../routing/session-key.js";
|
||||
import { theme } from "../terminal/theme.js";
|
||||
|
||||
@@ -158,10 +155,7 @@ const isAccountEnabled = (account: unknown): boolean => {
|
||||
const asRecord = (value: unknown): Record<string, unknown> | null =>
|
||||
value && typeof value === "object" ? (value as Record<string, unknown>) : null;
|
||||
|
||||
const formatProbeLine = (
|
||||
probe: unknown,
|
||||
opts: { botUsernames?: string[] } = {},
|
||||
): string | null => {
|
||||
const formatProbeLine = (probe: unknown, opts: { botUsernames?: string[] } = {}): string | null => {
|
||||
const record = asRecord(probe);
|
||||
if (!record) return null;
|
||||
const ok = typeof record.ok === "boolean" ? record.ok : undefined;
|
||||
@@ -203,7 +197,8 @@ const formatAccountProbeTiming = (summary: ChannelAccountHealthSummary): string
|
||||
|
||||
const accountId = summary.accountId || "default";
|
||||
const botRecord = asRecord(probe.bot);
|
||||
const botUsername = botRecord && typeof botRecord.username === "string" ? botRecord.username : null;
|
||||
const botUsername =
|
||||
botRecord && typeof botRecord.username === "string" ? botRecord.username : null;
|
||||
const handle = botUsername ? `@${botUsername}` : accountId;
|
||||
const timing = elapsedMs != null ? `${elapsedMs}ms` : "ok";
|
||||
|
||||
@@ -268,11 +263,9 @@ export const formatHealthChannelLines = (
|
||||
const listSummaries =
|
||||
accountMode === "all"
|
||||
? Object.values(accountSummaries)
|
||||
: filteredSummaries ?? (channelSummary.accounts ? Object.values(accountSummaries) : []);
|
||||
: (filteredSummaries ?? (channelSummary.accounts ? Object.values(accountSummaries) : []));
|
||||
const baseSummary =
|
||||
filteredSummaries && filteredSummaries.length > 0
|
||||
? filteredSummaries[0]
|
||||
: channelSummary;
|
||||
filteredSummaries && filteredSummaries.length > 0 ? filteredSummaries[0] : channelSummary;
|
||||
const botUsernames = listSummaries
|
||||
? listSummaries
|
||||
.map((account) => {
|
||||
@@ -285,8 +278,7 @@ export const formatHealthChannelLines = (
|
||||
const linked = typeof baseSummary.linked === "boolean" ? baseSummary.linked : null;
|
||||
if (linked !== null) {
|
||||
if (linked) {
|
||||
const authAgeMs =
|
||||
typeof baseSummary.authAgeMs === "number" ? baseSummary.authAgeMs : null;
|
||||
const authAgeMs = typeof baseSummary.authAgeMs === "number" ? baseSummary.authAgeMs : null;
|
||||
const authLabel = authAgeMs != null ? ` (auth age ${Math.round(authAgeMs / 60000)}m)` : "";
|
||||
lines.push(`${label}: linked${authLabel}`);
|
||||
} else {
|
||||
@@ -431,7 +423,8 @@ export async function getHealthSnapshot(params?: {
|
||||
}
|
||||
}
|
||||
|
||||
const probeRecord = probe && typeof probe === "object" ? (probe as Record<string, unknown>) : null;
|
||||
const probeRecord =
|
||||
probe && typeof probe === "object" ? (probe as Record<string, unknown>) : null;
|
||||
const bot =
|
||||
probeRecord && typeof probeRecord.bot === "object"
|
||||
? (probeRecord.bot as { username?: string | null })
|
||||
@@ -637,14 +630,15 @@ export async function healthCommand(
|
||||
}
|
||||
return byChannel;
|
||||
})();
|
||||
const channelLines = Object.keys(accountIdsByChannel).length > 0
|
||||
? formatHealthChannelLines(summary, {
|
||||
accountMode: opts.verbose ? "all" : "default",
|
||||
accountIdsByChannel,
|
||||
})
|
||||
: formatHealthChannelLines(summary, {
|
||||
accountMode: opts.verbose ? "all" : "default",
|
||||
});
|
||||
const channelLines =
|
||||
Object.keys(accountIdsByChannel).length > 0
|
||||
? formatHealthChannelLines(summary, {
|
||||
accountMode: opts.verbose ? "all" : "default",
|
||||
accountIdsByChannel,
|
||||
})
|
||||
: formatHealthChannelLines(summary, {
|
||||
accountMode: opts.verbose ? "all" : "default",
|
||||
});
|
||||
for (const line of channelLines) {
|
||||
runtime.log(styleHealthChannelLine(line));
|
||||
}
|
||||
@@ -690,7 +684,9 @@ export async function healthCommand(
|
||||
runtime.log(info(`Heartbeat interval: ${heartbeatParts.join(", ")}`));
|
||||
}
|
||||
if (displayAgents.length === 0) {
|
||||
runtime.log(info(`Session store: ${summary.sessions.path} (${summary.sessions.count} entries)`));
|
||||
runtime.log(
|
||||
info(`Session store: ${summary.sessions.path} (${summary.sessions.count} entries)`),
|
||||
);
|
||||
if (summary.sessions.recent.length > 0) {
|
||||
for (const r of summary.sessions.recent) {
|
||||
runtime.log(
|
||||
|
||||
@@ -226,7 +226,7 @@ export async function statusCommand(
|
||||
const storeLabel =
|
||||
summary.sessions.paths.length > 1
|
||||
? `${summary.sessions.paths.length} stores`
|
||||
: summary.sessions.paths[0] ?? "unknown";
|
||||
: (summary.sessions.paths[0] ?? "unknown");
|
||||
|
||||
const overviewRows = [
|
||||
{ Item: "Dashboard", Value: dashboard },
|
||||
|
||||
@@ -385,8 +385,9 @@ describe("statusCommand", () => {
|
||||
const payload = JSON.parse((runtime.log as vi.Mock).mock.calls.at(-1)?.[0]);
|
||||
expect(payload.sessions.count).toBe(2);
|
||||
expect(payload.sessions.paths.length).toBe(2);
|
||||
expect(payload.sessions.recent.some((sess: { key?: string }) => sess.key === "agent:ops:main"))
|
||||
.toBe(true);
|
||||
expect(
|
||||
payload.sessions.recent.some((sess: { key?: string }) => sess.key === "agent:ops:main"),
|
||||
).toBe(true);
|
||||
|
||||
if (originalAgents) mocks.listAgentsForGateway.mockImplementation(originalAgents);
|
||||
if (originalResolveStorePath)
|
||||
|
||||
@@ -463,10 +463,7 @@ function isObjectSchema(schema: JsonSchemaObject): boolean {
|
||||
}
|
||||
|
||||
function mergeObjectSchema(base: JsonSchemaObject, extension: JsonSchemaObject): JsonSchemaObject {
|
||||
const mergedRequired = new Set<string>([
|
||||
...(base.required ?? []),
|
||||
...(extension.required ?? []),
|
||||
]);
|
||||
const mergedRequired = new Set<string>([...(base.required ?? []), ...(extension.required ?? [])]);
|
||||
const merged: JsonSchemaObject = {
|
||||
...base,
|
||||
...extension,
|
||||
@@ -598,12 +595,17 @@ function applyPluginSchemas(schema: ConfigSchema, plugins: PluginUiMetadata[]):
|
||||
|
||||
for (const plugin of plugins) {
|
||||
if (!plugin.configSchema) continue;
|
||||
const entrySchema = entryBase ? cloneSchema(entryBase) : ({ type: "object" } as JsonSchemaObject);
|
||||
const entrySchema = entryBase
|
||||
? cloneSchema(entryBase)
|
||||
: ({ type: "object" } as JsonSchemaObject);
|
||||
const entryObject = asSchemaObject(entrySchema) ?? ({ type: "object" } as JsonSchemaObject);
|
||||
const baseConfigSchema = asSchemaObject(entryObject.properties?.config);
|
||||
const pluginSchema = asSchemaObject(plugin.configSchema);
|
||||
const nextConfigSchema =
|
||||
baseConfigSchema && pluginSchema && isObjectSchema(baseConfigSchema) && isObjectSchema(pluginSchema)
|
||||
baseConfigSchema &&
|
||||
pluginSchema &&
|
||||
isObjectSchema(baseConfigSchema) &&
|
||||
isObjectSchema(pluginSchema)
|
||||
? mergeObjectSchema(baseConfigSchema, pluginSchema)
|
||||
: cloneSchema(plugin.configSchema);
|
||||
|
||||
@@ -683,10 +685,7 @@ export function buildConfigSchema(params?: {
|
||||
const mergedHints = applySensitiveHints(
|
||||
applyChannelHints(applyPluginHints(base.uiHints, plugins), channels),
|
||||
);
|
||||
const mergedSchema = applyChannelSchemas(
|
||||
applyPluginSchemas(base.schema, plugins),
|
||||
channels,
|
||||
);
|
||||
const mergedSchema = applyChannelSchemas(applyPluginSchemas(base.schema, plugins), channels);
|
||||
return {
|
||||
...base,
|
||||
schema: mergedSchema,
|
||||
|
||||
@@ -56,9 +56,7 @@ function resolveAccountConfig(
|
||||
const direct = accounts[accountId] as TelegramAccountConfig | undefined;
|
||||
if (direct) return direct;
|
||||
const normalized = normalizeAccountId(accountId);
|
||||
const matchKey = Object.keys(accounts).find(
|
||||
(key) => normalizeAccountId(key) === normalized,
|
||||
);
|
||||
const matchKey = Object.keys(accounts).find((key) => normalizeAccountId(key) === normalized);
|
||||
return matchKey ? (accounts[matchKey] as TelegramAccountConfig | undefined) : undefined;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user