Files
boss/local-agent/health-summary.mjs
2026-06-08 12:22:50 +08:00

98 lines
3.6 KiB
JavaScript

function trimText(value, maxLength = 160) {
const text = typeof value === "string" ? value.trim() : "";
if (!text) {
return undefined;
}
return text.length > maxLength ? `${text.slice(0, maxLength)}...` : text;
}
function summarizePoll(poll) {
if (!poll || typeof poll !== "object") {
return null;
}
return {
at: trimText(poll.at, 80),
ok: poll.ok === true,
status: Number.isFinite(Number(poll.status)) ? Number(poll.status) : undefined,
};
}
function summarizeActiveMasterTask(activeMasterTask) {
if (!activeMasterTask || typeof activeMasterTask !== "object") {
return null;
}
return {
taskId: trimText(activeMasterTask.taskId, 80),
status: trimText(activeMasterTask.status, 80),
startedAt: trimText(activeMasterTask.startedAt, 80),
completedAt: trimText(activeMasterTask.completedAt, 80),
};
}
function summarizeReliableOutbox(runtime) {
const replay = runtime?.lastReliableOutboxReplay;
return {
busy: runtime?.reliableOutboxReplayBusy === true,
startedAt: trimText(runtime?.lastReliableOutboxReplayStartedAt, 80),
replayedAt: trimText(runtime?.lastReliableOutboxReplayAt, 80),
attempted: Number.isFinite(Number(replay?.attempted)) ? Number(replay.attempted) : 0,
sent: Number.isFinite(Number(replay?.sent)) ? Number(replay.sent) : 0,
retained: Number.isFinite(Number(replay?.retained)) ? Number(replay.retained) : 0,
stoppedByBudget: replay?.stoppedByBudget === true,
error: trimText(replay?.error),
};
}
function summarizeCodexAppServer(runtime) {
return {
metadataAtMs: Number.isFinite(Number(runtime?.codexAppServerCapabilityMetadataAtMs))
? Number(runtime.codexAppServerCapabilityMetadataAtMs)
: undefined,
refreshBusy: runtime?.codexAppServerCapabilityMetadataRefreshBusy === true,
lastError: trimText(runtime?.codexAppServerCapabilityMetadataError),
skippedAt: trimText(runtime?.codexAppServerCapabilityMetadataSkippedAt, 80),
skipReason: trimText(runtime?.codexAppServerCapabilityMetadataSkipReason, 120),
};
}
export function buildLocalAgentHealthSummary(config = {}, runtime = {}) {
return {
ok: runtime.lastHeartbeatOk === true,
service: "boss-local-agent",
deviceId: trimText(config.deviceId, 120),
now: new Date().toISOString(),
heartbeat: {
at: trimText(runtime.lastHeartbeatAt, 80),
ok: runtime.lastHeartbeatOk === true,
status: Number.isFinite(Number(runtime.lastHeartbeatStatus))
? Number(runtime.lastHeartbeatStatus)
: undefined,
},
masterTask: {
busy: runtime.masterTaskBusy === true,
active: summarizeActiveMasterTask(runtime.activeMasterTask),
lastPoll: summarizePoll(runtime.lastMasterTaskPoll),
},
outbox: summarizeReliableOutbox(runtime),
skills: {
syncBusy: runtime.skillSyncBusy === true,
syncAt: trimText(runtime.lastSkillSyncAt, 80),
syncOk: runtime.lastSkillSyncOk === true,
syncStatus: Number.isFinite(Number(runtime.lastSkillSyncStatus))
? Number(runtime.lastSkillSyncStatus)
: undefined,
count: Array.isArray(runtime.lastSkills) ? runtime.lastSkills.length : 0,
lifecycleBusy: runtime.skillLifecycleBusy === true,
lastLifecyclePoll: summarizePoll(runtime.lastSkillLifecyclePoll),
},
projectDiscovery: {
at: trimText(runtime.lastProjectDiscoveryAt, 80),
ok: runtime.lastProjectDiscoveryOk === true,
summary: trimText(runtime.lastProjectDiscoverySummary, 160),
skippedAt: trimText(runtime.lastProjectDiscoverySkippedAt, 80),
skipReason: trimText(runtime.lastProjectDiscoverySkipReason, 120),
},
codexAppServer: summarizeCodexAppServer(runtime),
};
}