openskynet / src /commands /status-all /report-lines.ts
Darochin's picture
Mirror OpenSkyNet workspace snapshot from Git HEAD
fc93158 verified
import type { ProgressReporter } from "../../cli/progress.js";
import { getTerminalTableWidth, renderTable } from "../../terminal/table.js";
import { isRich, theme } from "../../terminal/theme.js";
import { groupChannelIssuesByChannel } from "./channel-issues.js";
import { appendStatusAllDiagnosis } from "./diagnosis.js";
import { formatTimeAgo } from "./format.js";
type OverviewRow = { Item: string; Value: string };
type ChannelsTable = {
rows: Array<{
id: string;
label: string;
enabled: boolean;
state: "ok" | "warn" | "off" | "setup";
detail: string;
}>;
details: Array<{
title: string;
columns: string[];
rows: Array<Record<string, string>>;
}>;
};
type ChannelIssueLike = {
channel: string;
message: string;
};
type AgentStatusLike = {
agents: Array<{
id: string;
name?: string | null;
bootstrapPending?: boolean | null;
sessionsCount: number;
lastActiveAgeMs?: number | null;
sessionsPath: string;
}>;
};
export async function buildStatusAllReportLines(params: {
progress: ProgressReporter;
overviewRows: OverviewRow[];
channels: ChannelsTable;
channelIssues: ChannelIssueLike[];
agentStatus: AgentStatusLike;
connectionDetailsForReport: string;
diagnosis: Omit<
Parameters<typeof appendStatusAllDiagnosis>[0],
"lines" | "progress" | "muted" | "ok" | "warn" | "fail" | "connectionDetailsForReport"
>;
}) {
const rich = isRich();
const heading = (text: string) => (rich ? theme.heading(text) : text);
const ok = (text: string) => (rich ? theme.success(text) : text);
const warn = (text: string) => (rich ? theme.warn(text) : text);
const fail = (text: string) => (rich ? theme.error(text) : text);
const muted = (text: string) => (rich ? theme.muted(text) : text);
const tableWidth = getTerminalTableWidth();
const overview = renderTable({
width: tableWidth,
columns: [
{ key: "Item", header: "Item", minWidth: 10 },
{ key: "Value", header: "Value", flex: true, minWidth: 24 },
],
rows: params.overviewRows,
});
const channelRows = params.channels.rows.map((row) => ({
channelId: row.id,
Channel: row.label,
Enabled: row.enabled ? ok("ON") : muted("OFF"),
State:
row.state === "ok"
? ok("OK")
: row.state === "warn"
? warn("WARN")
: row.state === "off"
? muted("OFF")
: theme.accentDim("SETUP"),
Detail: row.detail,
}));
const channelIssuesByChannel = groupChannelIssuesByChannel(params.channelIssues);
const channelRowsWithIssues = channelRows.map((row) => {
const issues = channelIssuesByChannel.get(row.channelId) ?? [];
if (issues.length === 0) {
return row;
}
const issue = issues[0];
const suffix = ` · ${warn(`gateway: ${String(issue.message).slice(0, 90)}`)}`;
return {
...row,
State: warn("WARN"),
Detail: `${row.Detail}${suffix}`,
};
});
const channelsTable = renderTable({
width: tableWidth,
columns: [
{ key: "Channel", header: "Channel", minWidth: 10 },
{ key: "Enabled", header: "Enabled", minWidth: 7 },
{ key: "State", header: "State", minWidth: 8 },
{ key: "Detail", header: "Detail", flex: true, minWidth: 28 },
],
rows: channelRowsWithIssues,
});
const agentRows = params.agentStatus.agents.map((a) => ({
Agent: a.name?.trim() ? `${a.id} (${a.name.trim()})` : a.id,
BootstrapFile:
a.bootstrapPending === true
? warn("PRESENT")
: a.bootstrapPending === false
? ok("ABSENT")
: "unknown",
Sessions: String(a.sessionsCount),
Active: a.lastActiveAgeMs != null ? formatTimeAgo(a.lastActiveAgeMs) : "unknown",
Store: a.sessionsPath,
}));
const agentsTable = renderTable({
width: tableWidth,
columns: [
{ key: "Agent", header: "Agent", minWidth: 12 },
{ key: "BootstrapFile", header: "Bootstrap file", minWidth: 14 },
{ key: "Sessions", header: "Sessions", align: "right", minWidth: 8 },
{ key: "Active", header: "Active", minWidth: 10 },
{ key: "Store", header: "Store", flex: true, minWidth: 34 },
],
rows: agentRows,
});
const lines: string[] = [];
lines.push(heading("OpenClaw status --all"));
lines.push("");
lines.push(heading("Overview"));
lines.push(overview.trimEnd());
lines.push("");
lines.push(heading("Channels"));
lines.push(channelsTable.trimEnd());
for (const detail of params.channels.details) {
lines.push("");
lines.push(heading(detail.title));
lines.push(
renderTable({
width: tableWidth,
columns: detail.columns.map((c) => ({
key: c,
header: c,
flex: c === "Notes",
minWidth: c === "Notes" ? 28 : 10,
})),
rows: detail.rows.map((r) => ({
...r,
...(r.Status === "OK"
? { Status: ok("OK") }
: r.Status === "WARN"
? { Status: warn("WARN") }
: {}),
})),
}).trimEnd(),
);
}
lines.push("");
lines.push(heading("Agents"));
lines.push(agentsTable.trimEnd());
lines.push("");
lines.push(heading("Diagnosis (read-only)"));
await appendStatusAllDiagnosis({
lines,
progress: params.progress,
muted,
ok,
warn,
fail,
connectionDetailsForReport: params.connectionDetailsForReport,
...params.diagnosis,
});
return lines;
}