/** Fetch /proc and ctx snapshots for /bin/baretop (preamble; no import). */ /** EWMA of last fetch wall time (ms); used when `BARE_TOP_FETCH_EWMA=1`. */ var bareTopFetchEwmaMs = -1 /** Last fallback proc batch concurrency (for jitter smoothing). */ var bareTopLastFallbackConc = -1 /** Soft cache for secondary proc/ctx reads (stale-while-refresh). */ var bareTopSecondaryCache = Object.create(null) /** * Keep in sync with `bareOsReadBareTopSnapshot` path list in packages/bare-os-booter/index.js * @type {readonly [string, string][]} */ var BARE_TOP_SNAPSHOT_PROC_ENTRIES = [ ['index', '/proc/bare_os/index.json'], ['version', '/proc/bare_os/version'], ['hostOs', '/proc/bare_os/host_os.json'], ['debug', '/proc/bare_os/debug.json'], ['sessionStats', '/proc/bare_os/session_stats'], ['quotas', '/proc/bare_os/quotas'], ['capabilitiesJson', '/proc/bare_os/capabilities.json'], ['capabilitiesNode', '/proc/bare_os/capabilities'], ['seedHandshake', '/proc/bare_os/seed_handshake'], ['bootstrap', '/proc/bare_os/bootstrap'], ['provenance', '/proc/bare_os/provenance'], ['snapshotHints', '/proc/bare_os/snapshot_hints.json'], ['stagingSlot', '/proc/bare_os/staging_slot'], ['peerHealth', '/proc/bare_os/peer_health'], ['pearIpc', '/proc/bare_os/pear_ipc.json'], ['pearIpcHealth', '/proc/bare_os/pear_ipc_health.json'], ['pearTrust', '/proc/bare_os/pear_trust.json'], ['replication', '/proc/bare_os/replication'], ['replicationBackpressure', '/proc/bare_os/replication_backpressure.json'], ['swarm', '/proc/bare_os/swarm'], ['syncWindow', '/proc/bare_os/sync_window.json'], ['clock', '/proc/bare_os/clock.json'], ['openssh', '/proc/bare_os/openssh.json'], ['hdmsHealth', '/proc/bare_os/hdms_health.json'], ['hdmsHints', '/proc/bare_os/hdms_hints.json'], ['dhtStatus', '/proc/bare_os/dht_status.json'], ['udxExtended', '/proc/bare_os/udx_extended.json'], ['ipcBackpressure', '/proc/bare_os/ipc_backpressure.json'], ['delegateRed', '/proc/bare_os/delegate_red.json'], ['gitDelegateStats', '/proc/bare_os/git_delegate_stats.json'], ['kernelProgram', '/proc/bare_os/kernel_program.json'], ['gitLfsPointerStats', '/proc/bare_os/git_lfs_pointer_stats.json'], ['workerBudget', '/proc/bare_os/worker_budget.json'], ['sandboxProfile', '/proc/bare_os/sandbox_profile.json'], ['rlimits', '/proc/bare_os/rlimits.json'], ['extensions', '/proc/bare_os/extensions.json'], ['initdDag', '/proc/bare_os/initd_dag.json'], ['bootGraph', '/proc/bare_os/boot_graph.json'], [ 'bootBudgetSummary', '/proc/bare_os/boot_budget_summary.json' ], ['processTable', '/proc/bare_os/process_table.json'], ['syscalls', '/proc/bare_os/syscalls.json'], ['metricsProm', '/proc/bare_os/metrics.prom'], ['protomuxWire', '/proc/bare_os/protomux.json'], ['securityPosture', '/proc/bare_os/security_posture.json'], ['processIo', '/proc/bare_os/process_io.json'], ['processThreads', '/proc/bare_os/process_threads.json'], ['processMaps', '/proc/bare_os/process_maps.json'] ] /** Subset for BARE_TOP_SNAPSHOT_LITE=1 — keep keys subset of full list above. */ var BARE_TOP_SNAPSHOT_LITE_ENTRIES = [ ['index', '/proc/bare_os/index.json'], ['version', '/proc/bare_os/version'], ['hostOs', '/proc/bare_os/host_os.json'], ['replication', '/proc/bare_os/replication'], ['swarm', '/proc/bare_os/swarm'], ['syncWindow', '/proc/bare_os/sync_window.json'], ['processTable', '/proc/bare_os/process_table.json'], ['snapshotHints', '/proc/bare_os/snapshot_hints.json'] ] var BARE_TOP_SNAPSHOT_EXTENDED_HINT_KEYS = [ 'meshdrop', 'peerDetails', 'dhtScan', 'swarmDoctor', 'routeSummary', 'holepunchSummary' ] /** @param {unknown} buf @param {unknown} b4a @returns {string} */ function bareTopBufToString(buf, b4a) { if (buf == null) return '' if (typeof buf === 'string') return buf try { if (b4a && typeof b4a.toString === 'function') return b4a.toString(buf) } catch { /* fall through */ } try { return new TextDecoder().decode( buf instanceof Uint8Array ? buf : new Uint8Array(/** @type {ArrayLike} */ (buf)) ) } catch { return '' } } /** @param {string} s @returns {unknown} */ function bareTopJsonParse(s) { const t = String(s || '').trim() if (!t) return null try { return JSON.parse(t) } catch { return null } } /** * @param {Record} ctx * @param {string} path * @returns {Promise} */ async function bareTopReadProc(ctx, path) { const vfs = ctx.vfs if (!vfs || typeof vfs.readFile !== 'function') return '' try { const buf = await vfs.readFile(path) return bareTopBufToString(buf, ctx.b4a) } catch { return '' } } /** * @param {Record} ctx * @param {readonly [string, string][]} entries * @param {number} concurrency * @returns {Promise>} */ /** * @param {Record} ctx * @param {readonly [string, string][]} entries * @param {number} concurrency * @param {string[] | null} [errPaths] push failed paths (optional) */ async function bareTopReadProcBatch(ctx, entries, concurrency, errPaths) { /** @type {Record} */ const out = {} const vfs = ctx.vfs const conc = Math.max(1, Math.min(16, concurrency | 0) || 6) for (let i = 0; i < entries.length; i += conc) { const slice = entries.slice(i, i + conc) await Promise.all( slice.map(async ([key, path]) => { if (!vfs || typeof vfs.readFile !== 'function') { out[key] = '' return } try { const buf = await vfs.readFile(path) out[key] = bareTopBufToString(buf, ctx.b4a) } catch { out[key] = '' if (errPaths) errPaths.push(path) } }) ) } return out } /** * Read-through stale cache helper for secondary fields. * @param {string} key * @param {number} ttlMs * @param {() => Promise} producer * @returns {Promise<{ value: unknown, stale: boolean, freshAtMs: number, ttlMs: number }>} */ async function bareTopCachedSecondary(key, ttlMs, producer) { const now = Date.now() const cur = bareTopSecondaryCache[key] if (cur && typeof cur === 'object' && now - cur.atMs <= ttlMs) { return { value: cur.value, stale: false, freshAtMs: cur.atMs, ttlMs } } try { const value = await producer() bareTopSecondaryCache[key] = { value, atMs: now } return { value, stale: false, freshAtMs: now, ttlMs } } catch { if (cur && typeof cur === 'object') { return { value: cur.value, stale: true, freshAtMs: cur.atMs, ttlMs } } return { value: null, stale: true, freshAtMs: 0, ttlMs } } } /** * @param {unknown} o * @param {number} maxChars * @returns {string} */ function bareTopTruncateJsonPretty(o, maxChars) { const raw = JSON.stringify(o, null, 2) if (raw.length <= maxChars) return raw return raw.slice(0, Math.max(0, maxChars - 24)) + '\n… (truncated) …\n' } /** @param {number} n @returns {string} */ function bareTopFormatBytes(n) { const x = Number(n) if (!Number.isFinite(x) || x < 0) return '—' if (x < 1024) return String(Math.floor(x)) + ' B' if (x < 1048576) return (x / 1024).toFixed(1) + ' KiB' if (x < 1073741824) return (x / 1048576).toFixed(1) + ' MiB' return (x / 1073741824).toFixed(2) + ' GiB' } /** @param {number} ms @returns {string} */ function bareTopFormatDuration(ms) { const x = Number(ms) if (!Number.isFinite(x) || x < 0) return '—' if (x < 1000) return String(Math.floor(x)) + ' ms' if (x < 60000) return (x / 1000).toFixed(1) + ' s' if (x < 3600000) return Math.floor(x / 60000) + ' m' return (x / 3600000).toFixed(1) + ' h' } /** * @param {Record | null} m metrics live * @param {number} peers * @param {string | null | undefined} readErr optional snapshot read failure * @returns {number} 0–100 */ function bareTopHealthScore(m, peers, readErr) { return bareTopHealthScoreDetail(m, peers, readErr).score } /** * Subtractive score from 100 (penalty table): * - read_err: -28 * - no_metrics: -22 * - delegate_inflight: capped combined from active keys (count>0) + total inflight sum; max -12 * - replication stall: -20 when stallHint is a fault token OR replicationStall===true; * benign hints no_peers | length_unavailable | ok do not penalize (operational, not fault) * - boot_cold exceeded: -12; boot_stdlib exceeded: -12 * - initd_readiness.failed: up to -18; kernel initd.unit_failed_final: up to -10 * - peer_mismatch (replication.peerCount vs metrics peers): -8 when both finite and |Δ|>2 * - peers_invalid (peers<0): -5 * @param {Record | null} m * @param {number} peers * @param {string | null | undefined} readErr * @returns {{ score: number, breakdown: string }} */ function bareTopHealthScoreDetail(m, peers, readErr) { let score = 100 /** @type {string[]} */ const parts = ['base=100'] const errS = readErr != null ? String(readErr).trim() : '' if (errS) { const pen = 28 score -= pen parts.push('read_err=-' + pen) } const live = m && typeof m === 'object' ? /** @type {Record} */ (m) : null if (!live) { const pen = 22 score -= pen parts.push('no_metrics=-' + pen) } else { const delI = live.delegateInflight if (delI != null && typeof delI === 'object') { const o = /** @type {Record} */ (delI) const keys = Object.keys(o) let nActive = 0 let sum = 0 for (let i = 0; i < keys.length; i++) { const v = Math.max(0, Number(o[keys[i]]) || 0) sum += v if (v > 0) nActive++ } const penK = Math.min(10, nActive * 2) const penS = Math.min(20, sum * 2) const inflightCap = 12 const inflightTotal = Math.min(inflightCap, penK + penS) if (inflightTotal > 0) { score -= inflightTotal parts.push( 'inflight_-' + inflightTotal + '(activeKinds=' + nActive + ',sum=' + sum + ')' ) } } const rep = live.replicationLive && typeof live.replicationLive === 'object' ? /** @type {Record} */ (live.replicationLive) : null const stallExplicit = rep && rep.replicationStall === true ? true : false const hintRaw = rep && rep.stallHint const benignStallHints = new Set([ '', 'ok', 'no_peers', 'length_unavailable', '0', 'false', 'none', 'off', 'null', 'undefined' ]) if (stallExplicit) { const pen = 20 score -= pen parts.push('replication_stall_flag=-' + pen) } else if (hintRaw != null) { const hs = String(hintRaw).trim().toLowerCase() if (hs && !benignStallHints.has(hs)) { const pen = 20 score -= pen parts.push('stall_hint=-' + pen + '(' + hs + ')') } } const cold = live.bootBudgetCold && typeof live.bootBudgetCold === 'object' ? /** @type {Record} */ (live.bootBudgetCold) : null if (cold && cold.exceeded === true) { score -= 12 parts.push('boot_cold=-12') } const std = live.bootBudgetBareStdlib && typeof live.bootBudgetBareStdlib === 'object' ? /** @type {Record} */ (live.bootBudgetBareStdlib) : null if (std && std.exceeded === true) { score -= 12 parts.push('boot_stdlib=-12') } const ir = live.initdReadiness if (ir && typeof ir === 'object') { const failed = Number(/** @type {Record} */ (ir).failed) if (Number.isFinite(failed) && failed > 0) { const pen = Math.min(18, failed * 6) score -= pen parts.push('initd_failed_' + failed + '=-' + pen) } } const kc = live.kernelCounters if (kc && typeof kc === 'object') { const kf = Number( /** @type {Record} */ (kc)['initd.unit_failed_final'] ) if (Number.isFinite(kf) && kf > 0) { const pen = Math.min(10, kf * 2) score -= pen parts.push('initd_kc_' + kf + '=-' + pen) } } if ( rep && typeof rep.peerCount === 'number' && Number.isFinite(rep.peerCount) && rep.peerCount >= 0 && Number.isFinite(peers) && peers >= 0 ) { if (Math.abs(rep.peerCount - peers) > 2) { score -= 8 parts.push('peer_mismatch=-8') } } } if (peers < 0) { score -= 5 parts.push('peers_invalid=-5') } if (score < 0) score = 0 if (score > 100) score = 100 parts.push('=>' + score) return { score, breakdown: parts.join(' ') } } /** * @param {number} prev * @param {number} value * @param {number} alpha 0–1 * @returns {number} */ function bareTopEma(prev, value, alpha) { const a = Math.min(1, Math.max(0, alpha)) return prev * (1 - a) + value * a } /** * @param {Record} ctx * @param {Record} files * @param {string} key * @returns {Record | null} */ function bareTopParsedFile(files, key) { const t = files[key] if (!t) return null const p = bareTopJsonParse(t) return p && typeof p === 'object' ? /** @type {Record} */ (p) : null } /** * @param {Record} ctx * @returns {Promise>} */ /** One coalesced operator frame; keep VFS read fan-out bounded (batch size + concurrency). */ async function bareTopFetchSnapshot(ctx, fetchOpts) { const fetchStart = Date.now() let readErr = null const env = ctx.env && typeof ctx.env === 'object' ? /** @type {Record} */ (ctx.env) : {} const fo = fetchOpts && typeof fetchOpts === 'object' ? /** @type {{ forceLite?: boolean, activeTab?: string }} */ (fetchOpts) : null const concRaw = parseInt(env.BARE_TOP_FETCH_CONCURRENCY || '8', 10) const concurrency = Number.isFinite(concRaw) ? concRaw : 8 const fetchEwmaOn = env.BARE_TOP_FETCH_EWMA === '1' || env.BARE_TOP_FETCH_EWMA === 'true' const snapshotLite = fo && fo.forceLite === true ? true : env.BARE_TOP_SNAPSHOT_LITE === '1' || env.BARE_TOP_SNAPSHOT_LITE === 'true' const snapshotExtendedOn = env.BARE_TOP_SNAPSHOT_EXTENDED === '1' || env.BARE_TOP_SNAPSHOT_EXTENDED === 'true' const missingSignalsOn = env.BARE_TOP_MISSING_SIGNALS === '1' || env.BARE_TOP_MISSING_SIGNALS === 'true' const procEntryList = snapshotLite ? BARE_TOP_SNAPSHOT_LITE_ENTRIES : BARE_TOP_SNAPSHOT_PROC_ENTRIES const activeTab = String((fo && fo.activeTab) || 'overview').toLowerCase() const requestedKeys = (() => { if (snapshotLite) return BARE_TOP_SNAPSHOT_LITE_ENTRIES.map(([k]) => k) if (activeTab === 'processes') return [ 'index', 'version', 'hostOs', 'processTable', 'sessionStats', 'swarm', 'replication', 'snapshotHints' ] if (activeTab === 'network') return [ 'index', 'version', 'hostOs', 'swarm', 'replication', 'dhtStatus', 'udxExtended', 'snapshotHints' ] if ( missingSignalsOn && (activeTab === 'network' || activeTab === 'operator' || activeTab === 'diagnostics') ) { return BARE_TOP_SNAPSHOT_PROC_ENTRIES.map(([k]) => k).concat( BARE_TOP_SNAPSHOT_EXTENDED_HINT_KEYS ) } return BARE_TOP_SNAPSHOT_PROC_ENTRIES.map(([k]) => k) })() const snapshotProfile = snapshotLite || activeTab === 'processes' || activeTab === 'network' ? 'minimal' : snapshotExtendedOn || (missingSignalsOn && (activeTab === 'network' || activeTab === 'operator' || activeTab === 'diagnostics')) ? 'extended' : 'standard' /** @type {Record} */ let fileTexts = {} let fastAtMs = 0 let snapshotBatchBytes = 0 /** @type {Record | null} */ let metricsLiveFromSnap = null try { if (typeof ctx.bareOsReadBareTopSnapshot === 'function') { const r = await ctx.bareOsReadBareTopSnapshot( snapshotLite ? { lite: true, requestedKeys } : { profile: snapshotProfile, requestedKeys } ) if (r && typeof r === 'object') { const o = /** @type {Record} */ (r) const files = o.files if (files && typeof files === 'object') { for (const k of Object.keys(files)) { const v = files[k] if (typeof v === 'string') fileTexts[k] = v } } const am = o.atMs if (typeof am === 'number' && Number.isFinite(am)) fastAtMs = am if ( typeof o.snapshotBytes === 'number' && Number.isFinite(o.snapshotBytes) && o.snapshotBytes >= 0 ) { snapshotBatchBytes = o.snapshotBytes } const mlRaw = o.metricsLiveText if (typeof mlRaw === 'string' && mlRaw.trim()) { const mp = bareTopJsonParse(mlRaw) if (mp && typeof mp === 'object') { metricsLiveFromSnap = /** @type {Record} */ (mp) } } } } } catch (e) { readErr = (e && /** @type {{ message?: string }} */ (e).message) || String(e) } /** @type {string[]} */ const readErrPaths = [] if (Object.keys(fileTexts).length === 0) { let useConc = concurrency if (fetchEwmaOn && bareTopFetchEwmaMs >= 0) { const e = bareTopFetchEwmaMs if (e > 900) useConc = Math.max(2, concurrency - 3) else if (e > 500) useConc = Math.max(2, concurrency - 2) else if (e > 280) useConc = Math.max(2, concurrency - 1) } if (bareTopLastFallbackConc > 0) { if (useConc > bareTopLastFallbackConc + 1) useConc = bareTopLastFallbackConc + 1 if (useConc < bareTopLastFallbackConc - 1) useConc = bareTopLastFallbackConc - 1 } bareTopLastFallbackConc = useConc fileTexts = await bareTopReadProcBatch( ctx, procEntryList, useConc, readErrPaths ) } const atMs = fastAtMs || Date.now() /** @type {Record | null} */ let metricsLive = metricsLiveFromSnap /** @type {Record | null} */ let resources = null /** @type {Record | null} */ let features = null /** @type {Record | null} */ let netSummary = null /** @type {unknown} */ let initdGraph = null /** @type {Record | null} */ let fairnessSnapshot = null /** @type {unknown} */ let subprocessBridge = null /** @type {Record | null} */ let hostStats = null const ttl = { metricsLive: 300, resources: activeTab === 'diagnostics' ? 400 : 1500, features: activeTab === 'features' ? 500 : 2000, netSummary: activeTab === 'network' ? 300 : 1500, initdGraph: activeTab === 'initd' ? 400 : 2000, fairness: activeTab === 'operator' ? 500 : 2000, subprocess: activeTab === 'diagnostics' ? 600 : 2500, hostStats: activeTab === 'host' ? 500 : 2000, memRaw: activeTab === 'mem' ? 350 : 1400, loadavg: activeTab === 'cpu' ? 350 : 1200, cpuRaw: activeTab === 'cpu' ? 450 : 1800, diskstats: activeTab === 'disk' ? 450 : 1800 } /** @type {Record} */ const sectionTtl = {} try { if (typeof ctx.bareOsReadProcMetricsLive === 'function') { const o = ctx.bareOsReadProcMetricsLive() if (o && typeof o === 'object') metricsLive = /** @type {Record} */ (o) } } catch (e) { if (!readErr) readErr = (e && /** @type {{ message?: string }} */ (e).message) || String(e) } if (!metricsLive) { const ml = await bareTopCachedSecondary( 'metrics_live', ttl.metricsLive, async () => { const t = await bareTopReadProc(ctx, '/proc/bare_os/metrics_live.json') return bareTopJsonParse(t) } ) sectionTtl.metricsLive = { stale: ml.stale, freshAtMs: ml.freshAtMs, ttlMs: ml.ttlMs } if (ml.value && typeof ml.value === 'object') { metricsLive = /** @type {Record} */ (ml.value) } } try { if (typeof ctx.bareOsGetResourceStatus === 'function') { const o = ctx.bareOsGetResourceStatus() if (o && typeof o === 'object') resources = /** @type {Record} */ (o) } } catch { /* ignore */ } if (!resources) { const rs = await bareTopCachedSecondary( 'resources', ttl.resources, async () => { const t = await bareTopReadProc(ctx, '/proc/bare_os_resources') return bareTopJsonParse(t) } ) sectionTtl.resources = { stale: rs.stale, freshAtMs: rs.freshAtMs, ttlMs: rs.ttlMs } if (rs.value && typeof rs.value === 'object') { resources = /** @type {Record} */ (rs.value) } } const fs = await bareTopCachedSecondary( 'features', ttl.features, async () => { let fp = bareTopJsonParse(await bareTopReadProc(ctx, '/proc/bare_os/features')) if (!fp) fp = bareTopJsonParse(await bareTopReadProc(ctx, '/proc/bare_os_features')) return fp } ) sectionTtl.features = { stale: fs.stale, freshAtMs: fs.freshAtMs, ttlMs: fs.ttlMs } if (fs.value && typeof fs.value === 'object') { features = /** @type {Record} */ (fs.value) } const ns = await bareTopCachedSecondary( 'net_summary', ttl.netSummary, async () => { const netT = await bareTopReadProc(ctx, '/proc/bare_os/net_summary.json') return bareTopJsonParse(netT) } ) sectionTtl.netSummary = { stale: ns.stale, freshAtMs: ns.freshAtMs, ttlMs: ns.ttlMs } if (ns.value && typeof ns.value === 'object') { netSummary = /** @type {Record} */ (ns.value) } const ig = await bareTopCachedSecondary( 'initd_graph', ttl.initdGraph, async () => { const initT = await bareTopReadProc(ctx, '/proc/bare_os/initd_graph.json') return bareTopJsonParse(initT) } ) sectionTtl.initdGraph = { stale: ig.stale, freshAtMs: ig.freshAtMs, ttlMs: ig.ttlMs } initdGraph = ig.value if (initdGraph === null) { const alt = bareTopJsonParse(fileTexts.initdDag || '') initdGraph = alt } const fa = await bareTopCachedSecondary('fairness_snapshot', ttl.fairness, async () => { if (typeof ctx.bareOsReadDelegateFairnessSnapshot === 'function') { return ctx.bareOsReadDelegateFairnessSnapshot() } return null }) sectionTtl.fairnessSnapshot = { stale: fa.stale, freshAtMs: fa.freshAtMs, ttlMs: fa.ttlMs } if (fa.value && typeof fa.value === 'object') { fairnessSnapshot = /** @type {Record} */ (fa.value) } const sb = await bareTopCachedSecondary( 'subprocess_bridge', ttl.subprocess, async () => { if (typeof ctx.bareOsReadSubprocessBridgeSnapshot === 'function') { return ctx.bareOsReadSubprocessBridgeSnapshot() } return null } ) sectionTtl.subprocessBridge = { stale: sb.stale, freshAtMs: sb.freshAtMs, ttlMs: sb.ttlMs } subprocessBridge = sb.value const hs = await bareTopCachedSecondary('host_stats', ttl.hostStats, async () => { return ctx.bareOsHostStats || null }) sectionTtl.hostStats = { stale: hs.stale, freshAtMs: hs.freshAtMs, ttlMs: hs.ttlMs } if (hs.value && typeof hs.value === 'object') { hostStats = /** @type {Record} */ (hs.value) } const memC = await bareTopCachedSecondary('proc_meminfo', ttl.memRaw, async () => bareTopReadProc(ctx, '/proc/meminfo') ) sectionTtl.meminfo = { stale: memC.stale, freshAtMs: memC.freshAtMs, ttlMs: memC.ttlMs } const memRaw = typeof memC.value === 'string' ? memC.value : '' let meminfoLine = '' for (const line of memRaw.split('\n')) { const L = line.trim() if (L.startsWith('MemTotal:') || L.startsWith('MemAvailable:')) { meminfoLine = L break } } if (!meminfoLine) meminfoLine = memRaw.split('\n')[0]?.trim() || '' const loadC = await bareTopCachedSecondary('proc_loadavg', ttl.loadavg, async () => bareTopReadProc(ctx, '/proc/loadavg') ) sectionTtl.loadavg = { stale: loadC.stale, freshAtMs: loadC.freshAtMs, ttlMs: loadC.ttlMs } const loadavgLine = String(loadC.value || '').split('\n')[0]?.trim() || '' let cpuLine = '' let cpuCoreCount = 0 const cpuC = await bareTopCachedSecondary('proc_cpuinfo', ttl.cpuRaw, async () => bareTopReadProc(ctx, '/proc/cpuinfo') ) sectionTtl.cpuinfo = { stale: cpuC.stale, freshAtMs: cpuC.freshAtMs, ttlMs: cpuC.ttlMs } const cpuRaw = typeof cpuC.value === 'string' ? cpuC.value : '' for (const line of cpuRaw.split('\n')) { if (line.startsWith('model name') || line.startsWith('Model')) { cpuLine = line.replace(/^[^:]+:\s*/, '').trim().slice(0, 72) } const L = line.trim().toLowerCase() if (L.startsWith('processor') && L.includes(':')) cpuCoreCount++ } if (!cpuCoreCount) { const m = cpuRaw.match(/^processor\s*:/gim) if (m) cpuCoreCount = m.length } let swapinfoLine = '' for (const line of memRaw.split('\n')) { const L = line.trim() if (L.startsWith('SwapTotal:') || L.startsWith('SwapFree:')) { swapinfoLine = swapinfoLine ? swapinfoLine + ' ' + L : L } } const dsC = await bareTopCachedSecondary( 'proc_diskstats', ttl.diskstats, async () => bareTopReadProc(ctx, '/proc/diskstats') ) sectionTtl.diskstats = { stale: dsC.stale, freshAtMs: dsC.freshAtMs, ttlMs: dsC.ttlMs } const diskstatsRaw = typeof dsC.value === 'string' ? dsC.value : '' const diskstatsLine = diskstatsRaw.split('\n')[0]?.trim() || '' const hostOs = bareTopParsedFile(fileTexts, 'hostOs') const procIndex = bareTopParsedFile(fileTexts, 'index') || /** @type {Record} */ ({}) const procIndexAvailability = (() => { /** @type {Record} */ const out = Object.create(null) const nodes = procIndex && Array.isArray(procIndex.nodes) ? procIndex.nodes : [] const nodeSet = new Set() for (const n of nodes) { if (!n || typeof n !== 'object') continue const no = /** @type {Record} */ (n) if (typeof no.name === 'string') nodeSet.add(no.name) } for (const [k, p] of BARE_TOP_SNAPSHOT_PROC_ENTRIES) { const base = p.split('/').pop() || '' out[k] = nodeSet.has(base) || nodeSet.has(base.replace(/\.json$/i, '')) || (typeof fileTexts[k] === 'string' && fileTexts[k].length > 0) } for (const k of BARE_TOP_SNAPSHOT_EXTENDED_HINT_KEYS) { out[k] = out[k] === true || (typeof fileTexts[k] === 'string' && fileTexts[k].length > 0) } return out })() const metaAt = metricsLive && typeof metricsLive.atMs === 'number' ? metricsLive.atMs : atMs /** @type {Record | null>} */ const extra = {} for (const [key] of procEntryList) { if ( key === 'processTable' && metricsLive && metricsLive.processTable && typeof metricsLive.processTable === 'object' ) { extra[key] = /** @type {Record} */ ( metricsLive.processTable ) continue } extra[key] = bareTopParsedFile(fileTexts, key) } for (const key of BARE_TOP_SNAPSHOT_EXTENDED_HINT_KEYS) { if (extra[key] == null) extra[key] = bareTopParsedFile(fileTexts, key) } extra.procIndex = procIndex extra.procIndexAvailability = procIndexAvailability /** @type {Record} */ const snapshotBytesByKey = Object.create(null) for (const k of Object.keys(fileTexts)) { const v = fileTexts[k] snapshotBytesByKey[k] = typeof v === 'string' ? v.length : 0 } const fetchWallMs = Date.now() - fetchStart bareTopFetchEwmaMs = bareTopFetchEwmaMs < 0 ? fetchWallMs : bareTopFetchEwmaMs * 0.82 + fetchWallMs * 0.18 const peersN = Number(metricsLive && metricsLive.peers) || 0 const healthD = bareTopHealthScoreDetail(metricsLive, peersN, readErr) return { metricsLive, resources, features, initdGraph, netSummary, meminfoLine, swapinfoLine, loadavgLine, cpuLine, cpuCoreCount, diskstatsLine, diskstatsRaw, hostOs, atMs, metaAtMs: metaAt, readErr, readErrPaths, fileTexts, extra, fairnessSnapshot, subprocessBridge, hostStats, fetchWallMs, snapshotBatchBytes, snapshotBytesByKey, sectionTtl, snapshotProfile, snapshotRequestedKeys: requestedKeys, healthScore: healthD.score, healthBreakdown: healthD.breakdown, snapshotLite } }