Bump 0.5.35 and harden CPU monitoring fallback

This commit is contained in:
ekko
2026-05-23 10:43:07 +08:00
committed by ekko
parent f5846521e0
commit 56e7716302
2 changed files with 38 additions and 6 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hermes-web-ui", "name": "hermes-web-ui",
"version": "0.5.34", "version": "0.5.35",
"description": "Self-hosted AI chat dashboard for Hermes Agent — multi-model web UI with multi-platform integration", "description": "Self-hosted AI chat dashboard for Hermes Agent — multi-model web UI with multi-platform integration",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -96,6 +96,37 @@ function safeCpus(): ReturnType<typeof cpus> {
} }
} }
function readProcStatCpuTimes(): CpuTimesSample | null {
try {
const line = readFileSync('/proc/stat', 'utf-8').split(/\r?\n/, 1)[0]
const parts = line.trim().split(/\s+/)
if (parts[0] !== 'cpu') return null
const values = parts.slice(1).map(value => Number(value)).filter(Number.isFinite)
if (values.length < 4) return null
const idle = (values[3] || 0) + (values[4] || 0)
const total = values.reduce((sum, value) => sum + value, 0)
return total > 0 ? { idle, total } : null
} catch {
return null
}
}
function procCpuCount(): number {
try {
const cpuinfo = readFileSync('/proc/cpuinfo', 'utf-8')
const processors = cpuinfo.match(/^processor\s*:/gim)?.length || 0
if (processors > 0) return processors
const hardwareThreads = cpuinfo.match(/^CPU part\s*:/gim)?.length || 0
return hardwareThreads > 0 ? hardwareThreads : 0
} catch {
return 0
}
}
function safeCpuCount(): number {
return safeCpus().length || procCpuCount() || 1
}
function safeLoadAverage(): number[] { function safeLoadAverage(): number[] {
try { try {
return loadavg() return loadavg()
@@ -141,7 +172,8 @@ function readCpuTimes(): CpuTimesSample {
idle += cpu.times.idle idle += cpu.times.idle
total += Object.values(cpu.times).reduce((sum, value) => sum + value, 0) total += Object.values(cpu.times).reduce((sum, value) => sum + value, 0)
} }
return { idle, total } if (total > 0) return { idle, total }
return readProcStatCpuTimes() || { idle: 0, total: 0 }
} }
function sampleSystemCpuPercent(): number | null { function sampleSystemCpuPercent(): number | null {
@@ -173,7 +205,7 @@ function sampleWebCpuPercent(): number | null {
const elapsedMicros = (current.at - previous.at) * 1000 const elapsedMicros = (current.at - previous.at) * 1000
const used = (current.usage.user - previous.usage.user) + (current.usage.system - previous.usage.system) const used = (current.usage.user - previous.usage.user) + (current.usage.system - previous.usage.system)
if (elapsedMicros <= 0 || used < 0) return null if (elapsedMicros <= 0 || used < 0) return null
return clampPercent((used / elapsedMicros / Math.max(safeCpus().length, 1)) * 100) return clampPercent((used / elapsedMicros / safeCpuCount()) * 100)
} catch { } catch {
return null return null
} }
@@ -320,7 +352,7 @@ function sampleWindowsProcessCpuPercent(pid: number, cpuSeconds: number): number
const elapsedSeconds = (current.at - previous.at) / 1000 const elapsedSeconds = (current.at - previous.at) / 1000
const cpuDelta = current.cpuSeconds - previous.cpuSeconds const cpuDelta = current.cpuSeconds - previous.cpuSeconds
if (elapsedSeconds <= 0 || cpuDelta < 0) return 0 if (elapsedSeconds <= 0 || cpuDelta < 0) return 0
return clampPercent((cpuDelta / elapsedSeconds / Math.max(safeCpus().length, 1)) * 100) return clampPercent((cpuDelta / elapsedSeconds / safeCpuCount()) * 100)
} }
function collectWindowsProcessMetrics(pids: number[]): Map<number, Partial<ProcessUsage>> { function collectWindowsProcessMetrics(pids: number[]): Map<number, Partial<ProcessUsage>> {
@@ -463,7 +495,7 @@ export function createEmptyOpsRuntimeSnapshot(error?: string): OpsRuntimeSnapsho
platform: process.platform, platform: process.platform,
arch: process.arch, arch: process.arch,
uptimeSeconds: safeUptime(), uptimeSeconds: safeUptime(),
cpuCount: safeCpus().length, cpuCount: safeCpuCount(),
cpuPercent: 0, cpuPercent: 0,
loadAverage: safeLoadAverage(), loadAverage: safeLoadAverage(),
totalMemoryBytes: 0, totalMemoryBytes: 0,
@@ -565,7 +597,7 @@ export async function getOpsRuntimeSnapshot(): Promise<OpsRuntimeSnapshot> {
platform: process.platform, platform: process.platform,
arch: process.arch, arch: process.arch,
uptimeSeconds: safeUptime(), uptimeSeconds: safeUptime(),
cpuCount: safeCpus().length, cpuCount: safeCpuCount(),
cpuPercent: sampleSystemCpuPercent() ?? 0, cpuPercent: sampleSystemCpuPercent() ?? 0,
loadAverage: safeLoadAverage(), loadAverage: safeLoadAverage(),
totalMemoryBytes: systemMemory.totalMemoryBytes, totalMemoryBytes: systemMemory.totalMemoryBytes,