test: mock status command scan seam

This commit is contained in:
Peter Steinberger
2026-04-17 08:10:24 +01:00
parent ab726235bd
commit c93b2540ec

View File

@@ -175,6 +175,207 @@ function createDefaultSecurityAuditResult() {
};
}
async function createStatusServiceSummary(
service: ReturnType<(typeof mocks)["resolveGatewayService"]>,
) {
const [loaded, runtime, command] = await Promise.all([
service.isLoaded(),
service.readRuntime(),
service.readCommand(),
]);
return {
label: service.label,
installed: Boolean(command) || runtime?.status === "running",
loaded,
managedByOpenClaw: Boolean(command),
externallyManaged: !command && runtime?.status === "running",
loadedText: service.loadedText,
runtime,
runtimeShort: runtime?.pid ? `pid ${runtime.pid}` : null,
};
}
function createSessionStatusRows() {
const agents = mocks.listGatewayAgentsBasic().agents ?? [{ id: "main", name: "Main" }];
const byAgent = agents.map((agent: { id: string }) => {
const path = mocks.resolveStorePath("sessions", { agentId: agent.id });
const store = mocks.loadSessionStore(path) as Record<
string,
ReturnType<typeof createDefaultSessionStoreEntry>
>;
const recent = Object.entries(store).map(([key, entry]) => {
const contextTokens = typeof entry.contextTokens === "number" ? entry.contextTokens : null;
const freshTotal =
typeof entry.totalTokens === "number" && entry.totalTokensFresh !== false
? entry.totalTokens
: null;
return {
agentId: agent.id,
key,
kind: key.startsWith("+") ? ("direct" as const) : ("unknown" as const),
sessionId: entry.sessionId,
updatedAt: entry.updatedAt ?? null,
age: typeof entry.updatedAt === "number" ? Math.max(0, Date.now() - entry.updatedAt) : null,
thinkingLevel: entry.thinkingLevel,
verboseLevel: entry.verboseLevel,
inputTokens: entry.inputTokens,
outputTokens: entry.outputTokens,
totalTokens: freshTotal,
totalTokensFresh: freshTotal !== null,
cacheRead: entry.cacheRead,
cacheWrite: entry.cacheWrite,
remainingTokens:
freshTotal !== null && contextTokens !== null
? Math.max(0, contextTokens - freshTotal)
: null,
percentUsed:
freshTotal !== null && contextTokens
? Math.round((freshTotal / contextTokens) * 100)
: null,
model: typeof entry.model === "string" ? entry.model : null,
contextTokens,
flags: [
...(entry.verboseLevel ? [`verbose:${entry.verboseLevel}`] : []),
...(entry.thinkingLevel ? [`think:${entry.thinkingLevel}`] : []),
],
};
});
return { agentId: agent.id, path, count: recent.length, recent };
});
const recent = byAgent.flatMap((entry) => entry.recent);
return {
paths: byAgent.map((entry) => entry.path),
count: recent.length,
defaults: {
model: recent[0]?.model ?? "pi:opus",
contextTokens: recent[0]?.contextTokens ?? 10_000,
},
recent,
byAgent,
};
}
async function createMockStatusScanResult(params: { includePluginCompatibility?: boolean } = {}) {
const cfg = mocks.loadConfig();
const gatewayProbe = await mocks.probeGateway();
const gatewayReachable = gatewayProbe.ok === true;
const gatewayAuthWarning =
cfg.gateway?.auth?.token && typeof cfg.gateway.auth.token === "object"
? "gateway.auth.token unavailable"
: undefined;
const agentStatus = {
...mocks.listGatewayAgentsBasic(),
bootstrapPendingCount: 0,
totalSessions: 1,
agents: mocks.listGatewayAgentsBasic().agents.map((agent: { id: string; name?: string }) => ({
...agent,
bootstrapPending: false,
activeSessions: 1,
})),
};
const sessions = createSessionStatusRows();
const channelIssues = gatewayReachable
? [
{
channel: "signal",
accountId: "default",
message: "gateway: signal-cli unreachable",
},
{
channel: "imessage",
accountId: "default",
message: "gateway: imessage permission denied",
},
]
: [
{
channel: "signal",
accountId: "default",
message: "Channel error: signal-cli unreachable",
},
{
channel: "imessage",
accountId: "default",
message: "Channel error: imessage permission denied",
},
];
const pluginCompatibility =
params.includePluginCompatibility === false ? [] : mocks.buildPluginCompatibilityNotices();
return {
cfg,
sourceConfig: cfg,
secretDiagnostics: gatewayAuthWarning ? ["gateway.auth.token unavailable"] : [],
osSummary: {
platform: "darwin",
arch: "arm64",
release: "23.0.0",
label: "macos 14.0 (arm64)",
},
tailscaleMode: "off",
tailscaleDns: null,
tailscaleHttpsUrl: null,
update: {
root: "/tmp/openclaw",
installKind: "git",
packageManager: "pnpm",
git: {
root: "/tmp/openclaw",
branch: "main",
upstream: "origin/main",
dirty: false,
ahead: 0,
behind: 0,
fetchOk: true,
},
deps: {
manager: "pnpm",
status: "ok",
lockfilePath: "/tmp/openclaw/pnpm-lock.yaml",
markerPath: "/tmp/openclaw/node_modules/.modules.yaml",
},
registry: { latestVersion: "0.0.0" },
},
gatewayConnection: { url: "ws://127.0.0.1:18789" },
remoteUrlMissing: false,
gatewayMode: "local" as const,
gatewayProbeAuth: process.env.OPENCLAW_GATEWAY_TOKEN
? { token: process.env.OPENCLAW_GATEWAY_TOKEN }
: {},
gatewayProbeAuthWarning: gatewayAuthWarning,
gatewayProbe,
gatewayReachable,
gatewaySelf: gatewayProbe.presence ? { host: "gateway", ip: "127.0.0.1" } : null,
channelIssues,
agentStatus,
channels: {
rows: [
{ id: "whatsapp", label: "WhatsApp", enabled: true, state: "ok", detail: "linked" },
{ id: "signal", label: "Signal", enabled: true, state: "warn", detail: "gateway warning" },
{
id: "imessage",
label: "iMessage",
enabled: true,
state: "warn",
detail: "gateway warning",
},
],
details: [],
},
summary: {
runtimeVersion: null,
heartbeat: { defaultAgentId: "main", agents: [] },
channelSummary: [],
queuedSystemEvents: [],
tasks: mocks.getInspectableTaskRegistrySummary(),
taskAudit: mocks.getInspectableTaskAuditSummary(),
sessions,
},
memory: null,
memoryPlugin: { enabled: true, slot: "memory-core" },
pluginCompatibility,
};
}
async function withEnvVar<T>(key: string, value: string, run: () => Promise<T>): Promise<T> {
const prevValue = process.env[key];
process.env[key] = value;
@@ -517,7 +718,65 @@ vi.mock("../plugins/status.js", () => ({
`${notice.pluginId} ${notice.message}`,
}));
import { statusCommand } from "./status.js";
vi.mock("./status.scan.fast-json.js", () => ({
scanStatusJsonFast: vi.fn(async () =>
createMockStatusScanResult({ includePluginCompatibility: false }),
),
}));
vi.mock("./status.scan.js", () => ({
scanStatus: vi.fn(async () => createMockStatusScanResult()),
}));
vi.mock("./status-runtime-shared.ts", () => ({
loadStatusProviderUsageModule: vi.fn(async () => ({
formatUsageReportLines: vi.fn(() => []),
})),
resolveStatusGatewayHealth: vi.fn(async () => ({})),
resolveStatusSecurityAudit: vi.fn(async (input: unknown) =>
mocks.runSecurityAudit({
...(typeof input === "object" && input ? input : {}),
deep: false,
includeFilesystem: true,
includeChannelSecurity: true,
}),
),
resolveStatusUsageSummary: vi.fn(async () => undefined),
resolveStatusRuntimeSnapshot: vi.fn(
async (params: {
includeSecurityAudit?: boolean;
resolveSecurityAudit?: (input: unknown) => Promise<unknown>;
config: unknown;
sourceConfig: unknown;
}) => {
const securityAudit = params.includeSecurityAudit
? await (
params.resolveSecurityAudit ??
(async (input) =>
await mocks.runSecurityAudit({
...(typeof input === "object" && input ? input : {}),
deep: false,
includeFilesystem: true,
includeChannelSecurity: true,
}))
)({
config: params.config,
sourceConfig: params.sourceConfig,
})
: undefined;
return {
securityAudit,
usage: undefined,
health: undefined,
lastHeartbeat: null,
gatewayService: await createStatusServiceSummary(mocks.resolveGatewayService()),
nodeService: await createStatusServiceSummary(mocks.resolveNodeService()),
};
},
),
}));
import { statusCommand } from "./status.command.js";
const runtime = {
log: vi.fn(),