Files
bare-operating-system/packages/bare-os-coreutils/lib/baretop/baretop-ui-helpers.js
T
2026-08-18 18:11:28 -04:00

2634 lines
76 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** Pure UI helpers for /bin/baretop (preamble; no import). */
/** @type {Map<string, unknown>} */
var bareTopUiMemo = new Map()
var BARE_TOP_UI_MEMO_MAX = 256
/**
* @param {string} key
* @param {() => unknown} build
*/
function bareTopMemoGet(key, build) {
if (bareTopUiMemo.has(key)) return bareTopUiMemo.get(key)
const v = build()
bareTopUiMemo.set(key, v)
if (bareTopUiMemo.size > BARE_TOP_UI_MEMO_MAX) {
const it = bareTopUiMemo.keys().next()
if (!it.done) bareTopUiMemo.delete(it.value)
}
return v
}
/**
* @param {string} line
* @returns {{ label: string, value: string }[]}
*/
function bareTopParseMeminfoPairs(line) {
const s = String(line || '').trim()
const out = []
if (!s) return out
const re = /(\w+):\s*(\d+)\s*(\w+)?/g
let m
while ((m = re.exec(s)) !== null) {
out.push({
label: m[1],
value: m[2] + (m[3] ? ' ' + m[3] : '')
})
}
return out
}
/**
* @param {string} line
* @returns {{ pairs: { label: string, value: string }[], memTotal?: number, memAvail?: number }}
*/
function bareTopParseMeminfoMetrics(line) {
const pairs = bareTopParseMeminfoPairs(line)
let memTotal
let memAvail
for (const p of pairs) {
if (p.label === 'MemTotal') memTotal = parseInt(p.value, 10)
if (p.label === 'MemAvailable') memAvail = parseInt(p.value, 10)
}
return { pairs, memTotal, memAvail }
}
/**
* @param {string} line
* @returns {{ one: number, five: number, fifteen: number, running?: number, total?: number } | null}
*/
function bareTopParseLoadavg(line) {
const s = String(line || '').trim()
if (!s) return null
const parts = s.split(/\s+/)
if (parts.length < 3) return null
const one = parseFloat(parts[0])
const five = parseFloat(parts[1])
const fifteen = parseFloat(parts[2])
if (!Number.isFinite(one)) return null
const slash = parts[3] && parts[3].includes('/') ? parts[3].split('/') : null
return {
one,
five: Number.isFinite(five) ? five : one,
fifteen: Number.isFinite(fifteen) ? fifteen : one,
running: slash ? parseInt(slash[0], 10) : undefined,
total: slash ? parseInt(slash[1], 10) : undefined
}
}
/**
* @param {number} pct 0100
* @param {number} width
* @param {boolean} ascii
* @param {{ low?: string, mid?: string, hi?: string, reset: string }} pal
* @param {boolean} useColor
*/
function bareTopFormatMeterBar(pct, width, ascii, pal, useColor) {
const w = Math.max(2, width | 0)
const p = Math.min(100, Math.max(0, Number(pct) || 0))
const fill = Math.round((p / 100) * w)
const full = ascii ? '#' : '\u2588'
const empty = ascii ? '-' : '\u2591'
let s = ''
for (let i = 0; i < w; i++) {
const on = i < fill
if (!useColor) {
s += on ? full : empty
continue
}
const c =
p >= 95 ? pal.hi || ''
: p >= 80 ? pal.mid || ''
: on ? pal.low || ''
: ''
s += c + (on ? full : empty) + (c ? pal.reset : '')
}
return s
}
/**
* @param {string} text
* @param {number} maxLen
* @param {boolean} wordBoundary
*/
function bareTopTruncateCell(text, maxLen, wordBoundary) {
const t = String(text ?? '')
const m = Math.max(1, maxLen | 0)
if (t.length <= m) return t
if (!wordBoundary || m < 5) return t.slice(0, m - 1) + '\u2026'
let cut = t.lastIndexOf(' ', m - 1)
if (cut < m >> 1) cut = m - 1
return t.slice(0, cut).trimEnd() + '\u2026'
}
/**
* @param {unknown} pt process_table.json root
* @returns {Array<Record<string, unknown>>}
*/
function bareTopProcessRowsFromTable(pt) {
if (!pt || typeof pt !== 'object') return []
const o = /** @type {Record<string, unknown>} */ (pt)
const arr = o.processes
if (!Array.isArray(arr)) return []
return arr.filter((x) => x && typeof x === 'object')
}
/**
* @param {unknown} pt
* @param {number} nowMs
*/
function bareTopSessionUptimeLine(pt, nowMs) {
const rows = bareTopProcessRowsFromTable(pt)
let boot = 0
for (const r of rows) {
if (bareTopProcessPid(r) === 1) {
boot = bareTopProcessStartedMs(r)
break
}
}
if (!boot) return ''
return ' uptime ' + bareTopFormatProcAge(boot, nowMs) + ' (since bare-os-kernel row)'
}
/**
* @param {Record<string, unknown>} row
*/
function bareTopProcessPid(row) {
const n = Number(row.pid)
return Number.isFinite(n) ? n : 0
}
/**
* @param {Record<string, unknown>} row
* @param {'pid'|'name'|'state'|'time'|'nice'|'pri'|'cpu'} key
*/
/**
* @param {Record<string, unknown>} row
* @param {number} wallMs
*/
function bareTopEffectiveCpuPct(row, wallMs) {
const c = row.cpuPct ?? row.cpu
if (typeof c === 'number' && Number.isFinite(c)) return c
const delta = row.cpuMsDelta
const w = Number(wallMs) || 0
if (typeof delta === 'number' && Number.isFinite(delta) && w > 0)
return Math.min(100, Math.max(0, (delta / w) * 100))
return 0
}
/**
* @param {Record<string, unknown>} row
* @param {'pid'|'name'|'state'|'time'|'nice'|'pri'|'cpu'} key
* @param {number} [wallMs]
*/
function bareTopProcessSortKey(row, key, wallMs) {
if (key === 'name') return String(row.name || row.label || '').toLowerCase()
if (key === 'state') return String(row.state || '').toLowerCase()
if (key === 'time') return bareTopProcessStartedMs(row)
if (key === 'nice') return Number(row.nice ?? row.ni) || 0
if (key === 'pri') return Number(row.pri ?? row.priority) || 0
if (key === 'cpu') return bareTopEffectiveCpuPct(row, wallMs || 0)
return bareTopProcessPid(row)
}
/**
* @param {Record<string, unknown>} row
* @param {string} pfRaw
* @param {Record<string, string>} env
* @param {{ taggedPids?: Set<number>, taggedOnly?: boolean }} [opts]
*/
function bareTopProcessRowMatchesFilter(row, pfRaw, env, opts) {
const o = opts && typeof opts === 'object' ? opts : {}
const tagged = o.taggedPids
const taggedOnly = o.taggedOnly === true
const pid = bareTopProcessPid(row)
if (taggedOnly && tagged && tagged.size && !tagged.has(pid)) return false
const invertBase =
env.BARE_TOP_FILTER_INVERT === '1' || env.BARE_TOP_FILTER_INVERT === 'true'
let pf = String(pfRaw || '').trim()
let invert = invertBase
if (pf.startsWith('!')) {
pf = pf.slice(1).trim()
invert = !invert
}
if (!pf) return true
const regexEnv =
env.BARE_TOP_FILTER_REGEX === '1' || env.BARE_TOP_FILTER_REGEX === 'true'
const name = String(row.name || row.label || '')
const user = String(row.user || row.identity || '')
/** @type {RegExp | null} */
let re = null
if (regexEnv && pf.length) {
try {
re = new RegExp(pf, 'i')
} catch {
re = null
}
} else if (pf.length >= 2 && pf.charAt(0) === '/') {
const end = pf.lastIndexOf('/')
if (end > 0) {
try {
const flags = pf.slice(end + 1) || 'i'
re = new RegExp(pf.slice(1, end), flags)
} catch {
re = null
}
}
}
let match = false
if (re) match = re.test(name) || re.test(user)
else match = name.toLowerCase().includes(pf.toLowerCase())
return invert ? !match : match
}
/**
* @param {Record<string, unknown>[]} rows
* @param {'pid'|'name'|'state'|'time'|'nice'|'pri'|'cpu'} sortKey
* @param {boolean} asc
* @param {{ tertiaryPpid?: boolean, sortWallMs?: number }} [opts]
*/
function bareTopSortProcessRows(rows, sortKey, asc, opts) {
const o = opts && typeof opts === 'object' ? opts : {}
const tertiaryPpid = o.tertiaryPpid === true
const wallMs = Number(o.sortWallMs) || 0
const dir = asc ? 1 : -1
const memoKey =
'sort:' +
sortKey +
':' +
(asc ? '1' : '0') +
':' +
(tertiaryPpid ? '1' : '0') +
':' +
wallMs +
':' +
rows
.map((r) => {
const rr = /** @type {Record<string, unknown>} */ (r)
return (
String(rr.pid ?? '') +
'/' +
String(rr.ppid ?? '') +
'/' +
String(rr.name ?? '') +
'/' +
String(rr.state ?? '') +
'/' +
String(rr.startedAtMs ?? '') +
'/' +
String(rr.cpuPct ?? rr.cpu ?? '')
)
})
.join('|')
return /** @type {Record<string, unknown>[]} */ (
bareTopMemoGet(memoKey, () => {
const out = rows.slice()
out.sort((a, b) => {
const ka = bareTopProcessSortKey(a, sortKey, wallMs)
const kb = bareTopProcessSortKey(b, sortKey, wallMs)
let c = 0
if (typeof ka === 'number' && typeof kb === 'number') c = ka - kb
else c = String(ka).localeCompare(String(kb))
if (c !== 0) return c * dir
if (tertiaryPpid) {
const pa = Number(a.ppid) || 0
const pb = Number(b.ppid) || 0
if (pa !== pb) return (pa - pb) * dir
}
return bareTopProcessPid(a) - bareTopProcessPid(b)
})
return out
})
)
}
/**
* @param {string[]} cells
* @param {number[]} widths
* @param {('l'|'r')[]} align
* @param {number} maxLineLen
*/
function bareTopFormatFixedColumns(cells, widths, align, maxLineLen) {
const parts = []
let total = 0
for (let i = 0; i < cells.length && i < widths.length; i++) {
const w = Math.max(1, widths[i] | 0)
let c = bareTopTruncateCell(cells[i], w, true)
if (c.length > w) c = c.slice(0, w)
const pad = w - c.length
if (align[i] === 'r') {
parts.push(' '.repeat(Math.max(0, pad)) + c)
} else {
parts.push(c + ' '.repeat(Math.max(0, pad)))
}
total += w + (i < cells.length - 1 ? 1 : 0)
}
let line = parts.join(' ')
if (line.length > maxLineLen) line = line.slice(0, maxLineLen)
return line
}
/**
* @param {number} score 0100
* @param {number} width
* @param {boolean} ascii
*/
function bareTopHealthBarLine(score, width, ascii) {
const w = Math.max(4, width | 0)
const p = Math.min(100, Math.max(0, Math.round(Number(score) || 0)))
// Floor fill so the bar never reads a higher % than the integer score (round caused ~73% for 72/100).
const fill = Math.min(w, Math.floor((p * w) / 100))
const full = ascii ? '#' : '\u2588'
const empty = ascii ? '.' : '\u2591'
let bar = ''
for (let i = 0; i < w; i++) bar += i < fill ? full : empty
return String(p) + '/100 ' + bar
}
/**
* @param {string} title
* @param {number} cols
*/
function bareTopSectionRule(title, cols) {
const t = String(title || '').trim()
const c = Math.max(8, cols | 0)
const inner = c - 4
if (inner < 4) return t
const pad = inner - t.length
if (pad <= 0) return '\u2500 ' + t.slice(0, inner - 2) + ' \u2500'
const left = Math.floor(pad / 2)
const right = pad - left
return (
'\u2500'.repeat(Math.max(1, left)) + ' ' + t + ' ' + '\u2500'.repeat(Math.max(1, right))
)
}
/**
* Strip C0 controls except tab; keep printable + UTF-8 continuation for display safety.
* @param {string} s
*/
function bareTopSanitizeVisible(s) {
let t = String(s)
let o = ''
for (let i = 0; i < t.length; i++) {
const c = t.charCodeAt(i)
if (c === 9 || c === 10 || c === 13) o += t[i]
else if (c < 32) o += ' '
else o += t[i]
}
return o
}
/**
* @param {number} scrollTop
* @param {number} vis
* @param {string[]} wrapped
* @returns {string[]} visible slice (copy)
*/
function bareTopScrollSliceLines(wrapped, scrollTop, vis) {
const v = Math.max(1, vis | 0)
const s = Math.max(0, scrollTop | 0)
return wrapped.slice(s, s + v)
}
/**
* @param {unknown} row
* @returns {number}
*/
function bareTopProcessStartedMs(row) {
if (!row || typeof row !== 'object') return 0
const n = Number(/** @type {Record<string, unknown>} */ (row).startedAtMs)
return Number.isFinite(n) ? n : 0
}
/**
* @param {number} startedAtMs
* @param {number} nowMs
*/
function bareTopPad2(n) {
const x = n | 0
return x < 10 ? '0' + x : String(x)
}
function bareTopFormatProcAge(startedAtMs, nowMs) {
const t0 = Number(startedAtMs)
const now = Number(nowMs)
if (!Number.isFinite(t0) || t0 <= 0 || !Number.isFinite(now)) return ''
let sec = Math.max(0, Math.floor((now - t0) / 1000))
if (sec < 3600) {
const m = Math.floor(sec / 60)
const s = sec % 60
return m > 0 ? m + ':' + bareTopPad2(s) : String(s) + 's'
}
const h = Math.floor(sec / 3600)
sec %= 3600
const m = Math.floor(sec / 60)
const s = sec % 60
return h + ':' + bareTopPad2(m) + ':' + bareTopPad2(s)
}
/**
* Tree order: depth-first by ppid, stable by pid.
* @param {Record<string, unknown>[]} rows
*/
function bareTopProcessTreeOrder(rows) {
const byPid = new Map()
for (const r of rows) {
const p = bareTopProcessPid(r)
if (p) byPid.set(p, r)
}
const children = new Map()
for (const r of rows) {
const ppid = Number(r.ppid) || 0
if (!children.has(ppid)) children.set(ppid, [])
children.get(ppid).push(r)
}
for (const arr of children.values()) {
arr.sort((a, b) => bareTopProcessPid(a) - bareTopProcessPid(b))
}
/** @type {Record<string, unknown>[]} */
const out = []
function walk(pid, depth) {
const ch = children.get(pid)
if (!ch) return
for (const r of ch) {
out.push(Object.assign({}, r, { _treeDepth: depth }))
walk(bareTopProcessPid(r), depth + 1)
}
}
walk(0, 0)
for (const r of rows) {
const p = bareTopProcessPid(r)
const pp = Number(r.ppid) || 0
if (!byPid.has(pp) && pp === 0 && p) {
/* orphan roots not reached */
}
}
if (out.length === 0) return rows.map((r) => Object.assign({}, r, { _treeDepth: 0 }))
return out
}
/**
* @param {string} title
* @param {number} cols
* @param {boolean} ascii
*/
function bareTopSectionSeparator(title, cols, ascii) {
const rule = bareTopSectionRule(title, cols)
if (ascii) return '- ' + String(title || '') + ' ' + '-'.repeat(Math.max(4, cols - title.length - 4))
return rule
}
/**
* @param {unknown} o
* @param {number} maxRows
* @param {number} keyW
*/
function bareTopDelegateInflightTableLines(o, maxRows, keyW) {
if (!o || typeof o !== 'object') return []
const rec = /** @type {Record<string, unknown>} */ (o)
const pairs = Object.keys(rec)
.map((k) => ({ k, v: Number(rec[k]) || 0 }))
.sort((a, b) => b.v - a.v || a.k.localeCompare(b.k))
const lim = Math.min(maxRows, pairs.length)
/** @type {string[]} */
const out = []
const kw = Math.max(6, keyW | 0)
const vw = 8
for (let i = 0; i < lim; i++) {
const { k, v } = pairs[i]
const ks = bareTopTruncateCell(k, kw, true)
const padK = ' '.repeat(Math.max(0, kw - ks.length))
const vs = String(v).padStart(vw, ' ')
out.push(' ' + ks + padK + ' ' + vs)
}
if (pairs.length > lim) out.push(' … +' + (pairs.length - lim) + ' more keys')
return out
}
/**
* @param {unknown} o
* @param {number} cols
*/
/**
* @param {Record<string, unknown>} snap
*/
function bareTopLimitsMergedLines(snap) {
/** @type {string[]} */
const lines = []
const q =
snap &&
snap.extra &&
snap.extra.quotas &&
typeof snap.extra.quotas === 'object'
? /** @type {Record<string, unknown>} */ (snap.extra.quotas)
: null
const r =
snap &&
snap.extra &&
snap.extra.rlimits &&
typeof snap.extra.rlimits === 'object'
? /** @type {Record<string, unknown>} */ (snap.extra.rlimits)
: null
function row(prefix, o2, max) {
const keys = Object.keys(o2).slice(0, max)
for (const k of keys) {
const v = o2[k]
const s =
v != null && typeof v !== 'object'
? String(v)
: v && typeof v === 'object'
? '{…}'
: ''
lines.push(prefix + k + '=' + bareTopTruncateCell(s, 56, false))
}
}
if (q) {
lines.push(' quotas (operator caps — full detail on catalog tab)')
row(' ', q, 8)
}
if (r) {
lines.push(' rlimits (process limits mirror)')
row(' ', r, 8)
}
return lines
}
/**
* Human-readable key labels (matches baretop-tui bareTopHumanKey).
* @param {string} k
*/
function bareTopUiHumanKey(k) {
return String(k || '')
.replace(/([A-Z])/g, ' $1')
.replace(/_/g, ' ')
.replace(/\s+/g, ' ')
.trim()
.toLowerCase()
.replace(/^\w/, (c) => c.toUpperCase())
}
/**
* Flatten nested values to lines (no JSON); uses N/A for nulls.
* @param {string} prefix
* @param {unknown} v
* @param {number} depth
* @param {number} maxD
* @param {string[]} lines
* @param {number} maxKeys
*/
function bareTopUiFlatten(prefix, v, depth, maxD, lines, maxKeys) {
const na = 'N/A'
const pad = ' '.repeat(depth)
if (depth > maxD) {
lines.push(pad + (prefix ? bareTopUiHumanKey(prefix) + ': ' : '') + '\u2026')
return
}
if (v == null) {
lines.push(pad + (prefix ? bareTopUiHumanKey(prefix) + ': ' : '') + na)
return
}
const t = typeof v
if (t === 'string' || t === 'number' || t === 'boolean') {
let s = String(v)
if (t === 'string' && s.length > 800) s = s.slice(0, 797) + '\u2026'
lines.push(pad + (prefix ? bareTopUiHumanKey(prefix) + ': ' : '') + s)
return
}
if (Array.isArray(v)) {
const label = prefix ? bareTopUiHumanKey(prefix) + ': ' : ''
if (v.length === 0) {
lines.push(pad + label + '(empty)')
return
}
lines.push(pad + label + '(' + v.length + ' items)')
const lim = Math.min(v.length, 120)
for (let i = 0; i < lim; i++) {
const it = v[i]
if (it != null && typeof it === 'object' && !Array.isArray(it)) {
lines.push(pad + ' #' + i)
bareTopUiFlatten('', it, depth + 2, maxD, lines, maxKeys)
} else if (Array.isArray(it)) {
lines.push(pad + ' #' + i)
bareTopUiFlatten('', it, depth + 2, maxD, lines, maxKeys)
} else {
lines.push(
pad + ' #' + i + ': ' + (it == null ? na : String(it))
)
}
}
if (v.length > lim) lines.push(pad + ' \u2026 +' + (v.length - lim) + ' more')
return
}
if (t === 'object') {
const o = /** @type {Record<string, unknown>} */ (v)
const keys = Object.keys(o)
if (keys.length === 0) {
lines.push(pad + (prefix ? bareTopUiHumanKey(prefix) + ': ' : '') + '(empty)')
return
}
const slice = keys.slice(0, maxKeys)
if (prefix) {
lines.push(pad + bareTopUiHumanKey(prefix) + ':')
for (const k of slice) bareTopUiFlatten(k, o[k], depth + 1, maxD, lines, maxKeys)
} else {
for (const k of slice) bareTopUiFlatten(k, o[k], depth, maxD, lines, maxKeys)
}
if (keys.length > maxKeys)
lines.push(pad + '\u2026 +' + (keys.length - maxKeys) + ' keys')
}
}
/**
* @param {string} prefix
* @param {unknown} v
* @param {number} depth
* @param {number} maxD
* @param {number} maxKeys
* @param {number} maxLines
*/
function bareTopUiFlattenLimited(prefix, v, depth, maxD, maxKeys, maxLines) {
let sig = ''
try {
sig = JSON.stringify(v)
} catch {
sig = String(v)
}
const key =
'flatten:' +
prefix +
':' +
depth +
':' +
maxD +
':' +
maxKeys +
':' +
maxLines +
':' +
sig
return /** @type {string[]} */ (
bareTopMemoGet(key, () => {
const lines = []
bareTopUiFlatten(prefix, v, depth, maxD, lines, maxKeys)
const cap = Math.max(4, maxLines | 0)
if (lines.length > cap) {
return lines.slice(0, cap - 1).concat([' … (truncated)'])
}
return lines
})
)
}
/**
* One-line-ish summary for nested objects (no JSON braces in the TUI).
* @param {unknown} v
* @param {number} maxChars
*/
function bareTopFormatNestedBrief(v, maxChars) {
const m = Math.max(8, maxChars | 0)
if (v == null) return ''
const t = typeof v
if (t === 'string' || t === 'number' || t === 'boolean')
return bareTopTruncateCell(String(v), m, false)
if (t === 'bigint') return String(v)
if (t !== 'object') return bareTopTruncateCell(String(v), m, false)
const lines = bareTopUiFlattenLimited('', v, 0, 6, 80, 24)
const s = lines.join(' · ')
if (s.length <= m) return s
return s.slice(0, Math.max(4, m - 18)) + '\u2026(truncated)'
}
/**
* @param {unknown} v
* @param {number} maxChars
*/
function bareTopJsonSnippet(v, maxChars) {
const m = Math.max(8, maxChars | 0)
try {
if (v != null && typeof v === 'object')
return bareTopFormatNestedBrief(v, m)
if (typeof v === 'bigint') return String(v)
const s = JSON.stringify(v)
if (s.length <= m) return s
return s.slice(0, Math.max(4, m - 18)) + '\u2026(truncated)'
} catch {
return '(unserializable)'
}
}
/**
* @param {unknown} v
* @param {number} maxLen
*/
function bareTopFormatScalarTerminal(v, maxLen) {
const m = Math.max(4, maxLen | 0)
if (v == null) return ''
const t = typeof v
if (t === 'string' || t === 'number' || t === 'boolean' || t === 'bigint')
return bareTopTruncateCell(String(v), m, false)
if (t === 'object') return bareTopJsonSnippet(v, m)
return bareTopTruncateCell(String(v), m, false)
}
/**
* Format integers with grouped thousands (en-US style).
* @param {unknown} n
*/
function bareTopFormatIntGrouped(n) {
const x = Number(n)
if (!Number.isFinite(x)) return String(n)
const neg = x < 0
const i = Math.floor(Math.abs(x))
const s = String(i)
const g = []
for (let k = s.length; k > 0; k -= 3) g.push(s.slice(Math.max(0, k - 3), k))
return (neg ? '-' : '') + g.reverse().join(',')
}
/**
* Human duration for millisecond-ish counters (shared UI).
* @param {unknown} ms
*/
function bareTopFormatDurationMs(ms) {
const t = Number(ms)
if (!Number.isFinite(t) || t < 0) return ''
if (t < 1000) return Math.round(t) + 'ms'
if (t < 60000) return (t / 1000).toFixed(1) + 's'
if (t < 3600000) return Math.floor(t / 60000) + 'm'
return Math.floor(t / 3600000) + 'h'
}
/**
* Rx/tx bytes: use global bareTopFormatBytes from baretop-snapshot preamble when bundled.
* @param {unknown} n
*/
function bareTopNetFormatBytes(n) {
if (typeof bareTopFormatBytes === 'function') return bareTopFormatBytes(n)
const x = Number(n)
if (!Number.isFinite(x) || x < 0) return '\u2014'
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 {Record<string, unknown>} o
*/
function bareTopNetOrderedTopKeys(o) {
const priority = [
'schema',
'schemaVersion',
'topicHex',
'peerCount',
'replicationQueueDepth',
'peerFirewallAcceptedTotal',
'peerFirewallRejectedTotal',
'peerFirewallInboundTotal',
'peerFirewallOutboundTotal',
'seedHandshakeError',
'seedRole',
'atMs'
]
const seen = new Set()
/** @type {string[]} */
const out = []
for (const k of priority) {
if (Object.prototype.hasOwnProperty.call(o, k) && o[k] != null) {
out.push(k)
seen.add(k)
}
}
const rest = Object.keys(o)
.filter((k) => !seen.has(k))
.sort((a, b) => a.localeCompare(b))
return out.concat(rest)
}
/**
* @param {unknown} q
* @param {number} cols
*/
function bareTopNetReplicationQueueLines(q, cols) {
if (!q || typeof q !== 'object') return [' (null)']
const o = /** @type {Record<string, unknown>} */ (q)
/** @type {string[]} */
const lines = []
const scalars = [
'depth',
'pending',
'pendingCount',
'length',
'size',
'backlog',
'queued',
'inFlight',
'lastError',
'error',
'note',
'atMs'
]
for (const k of scalars) {
if (!Object.prototype.hasOwnProperty.call(o, k)) continue
const v = o[k]
if (v != null && typeof v !== 'object')
lines.push(' ' + k + ': ' + String(v))
}
for (const ak of ['items', 'queue', 'entries', 'pendingJobs']) {
if (Array.isArray(o[ak]))
lines.push(' ' + ak + ': ' + o[ak].length + ' entries')
}
const nestedKeys = Object.keys(o).filter((k) => {
const v = o[k]
return v != null && typeof v === 'object'
})
for (const nk of nestedKeys.slice(0, 6)) {
lines.push(' ' + nk + ': ' + bareTopJsonSnippet(o[nk], Math.max(24, cols - 14)))
}
if (!lines.length)
lines.push(' ' + bareTopJsonSnippet(o, Math.max(40, cols - 6)))
return lines
}
/**
* peer_firewall_stats / channel.js firewall shape: acceptedSessionCount, rejectedSessionCount, etc.
* @param {unknown} fw
* @param {number} cols
*/
function bareTopNetPeerFirewallLines(fw, cols) {
if (!fw || typeof fw !== 'object') return [' (null)']
const o = /** @type {Record<string, unknown>} */ (fw)
/** @type {string[]} */
const lines = []
const counts = [
'acceptedSessionCount',
'rejectedSessionCount',
'inboundSessionCount',
'outboundSessionCount'
]
for (const k of counts) {
if (typeof o[k] === 'number') lines.push(' ' + k + ': ' + bareTopFormatIntGrouped(o[k]))
}
if (typeof o.error === 'string' && o.error.trim())
lines.push(' error: ' + bareTopTruncateCell(o.error, cols - 8, true))
if (typeof o.note === 'string' && o.note.trim())
lines.push(' note: ' + bareTopTruncateCell(o.note, cols - 8, true))
for (const extra of ['transportBreakdown', 'saturationClass', 'wave9', 'wave10']) {
if (o[extra] != null && typeof o[extra] === 'object')
lines.push(
' ' +
extra +
': ' +
bareTopJsonSnippet(o[extra], Math.max(32, cols - 14))
)
}
if (!lines.length)
lines.push(' ' + bareTopJsonSnippet(o, Math.max(40, cols - 6)))
return lines
}
/**
* @param {unknown} b
* @param {number} cols
*/
function bareTopNetBsdBridgeLines(b, cols) {
if (!b || typeof b !== 'object') return [' (null)']
const o = /** @type {Record<string, unknown>} */ (b)
/** @type {string[]} */
const lines = []
for (const k of [
'schema',
'policyEnv',
'activeBridgedFds',
'bridgeErrors',
'guestSocketCount'
]) {
if (!Object.prototype.hasOwnProperty.call(o, k)) continue
const v = o[k]
if (v != null && typeof v !== 'object')
lines.push(' ' + k + ': ' + String(v))
}
if (typeof o.note === 'string' && o.note.trim())
lines.push(
' note: ' + bareTopTruncateCell(String(o.note), Math.max(20, cols - 10), true)
)
const rest = Object.keys(o).filter(
(k) => !['schema', 'policyEnv', 'note', 'activeBridgedFds', 'bridgeErrors', 'guestSocketCount'].includes(k)
)
for (const k of rest.slice(0, 8)) {
const v = o[k]
lines.push(
' ' +
k +
': ' +
bareTopFormatScalarTerminal(v, Math.max(16, cols - 12))
)
}
return lines.length ? lines : [' (empty)']
}
/**
* @param {unknown} net
* @param {unknown} metricsLive
*/
function bareTopNetHealthOverviewLines(net, metricsLive) {
/** @type {string[]} */
const parts = []
const peersMl =
metricsLive && typeof metricsLive === 'object'
? Number(/** @type {Record<string, unknown>} */ (metricsLive).peers)
: NaN
if (Number.isFinite(peersMl)) parts.push('peers_ml=' + bareTopFormatIntGrouped(peersMl))
if (net && typeof net === 'object') {
const o = /** @type {Record<string, unknown>} */ (net)
if (o.topicHex != null) parts.push('topic=' + String(o.topicHex).slice(0, 16))
if (typeof o.peerCount === 'number')
parts.push('peers_net=' + bareTopFormatIntGrouped(o.peerCount))
const err = o.seedHandshakeError
if (err != null && String(err).trim())
parts.push('seedErr=' + bareTopTruncateCell(String(err), 36, true))
const rd = o.replicationQueueDepth
if (typeof rd === 'number') parts.push('replQ=' + bareTopFormatIntGrouped(rd))
}
if (!parts.length) return []
return [' net ' + parts.join(' ') + ' (tab: network)']
}
/**
* Consolidated HDMS + DHT line for overview (traffic-light style).
* @param {Record<string, unknown>} snap
*/
function bareTopHdmsDhtTrafficLine(snap) {
const hd =
snap &&
snap.extra &&
snap.extra.hdmsHealth &&
typeof snap.extra.hdmsHealth === 'object'
? /** @type {Record<string, unknown>} */ (snap.extra.hdmsHealth)
: null
const dh =
snap &&
snap.extra &&
snap.extra.dhtStatus &&
typeof snap.extra.dhtStatus === 'object'
? /** @type {Record<string, unknown>} */ (snap.extra.dhtStatus)
: null
if (!hd && !dh) return ''
function grade(o) {
if (!o) return '?'
const e = o.error ?? o.err
if (e != null && String(e).trim()) return 'R'
const ok = o.ok ?? o.healthy ?? o.ready
if (ok === false) return 'R'
if (ok === true) return 'G'
return 'Y'
}
const bits = []
if (hd) {
bits.push('hdms[' + grade(hd) + ']=' + bareTopP2PKvString(hd, 5))
}
if (dh) {
bits.push('dht[' + grade(dh) + ']=' + bareTopP2PKvString(dh, 5))
}
return ' p2p ' + bits.join(' ')
}
/**
* @param {Record<string, unknown>} o
* @param {number} maxKeys
*/
function bareTopP2PKvString(o, maxKeys) {
return Object.keys(o)
.slice(0, maxKeys)
.map((k) => {
const v = o[k]
return k + '=' + (v != null && typeof v !== 'object' ? String(v) : bareTopJsonSnippet(v, 32))
})
.join(' ')
}
function bareTopP2PStackLines(snap) {
/** @type {string[]} */
const out = []
const traffic = bareTopHdmsDhtTrafficLine(/** @type {Record<string, unknown>} */ (snap))
if (traffic) {
out.push(traffic)
return out
}
const hd =
snap &&
snap.extra &&
snap.extra.hdmsHealth &&
typeof snap.extra.hdmsHealth === 'object'
? /** @type {Record<string, unknown>} */ (snap.extra.hdmsHealth)
: null
const dh =
snap &&
snap.extra &&
snap.extra.dhtStatus &&
typeof snap.extra.dhtStatus === 'object'
? /** @type {Record<string, unknown>} */ (snap.extra.dhtStatus)
: null
if (hd)
out.push(' hdms ' + bareTopTruncateCell(bareTopP2PKvString(hd, 8), 100, false))
if (dh)
out.push(' dht ' + bareTopTruncateCell(bareTopP2PKvString(dh, 8), 100, false))
return out
}
/**
* @typedef {{ maxLines?: number, filter?: string, wideTwoCol?: boolean }} BareTopNetTabOpts
* @param {unknown} net
* @param {number} cols
* @param {BareTopNetTabOpts | null} [opts]
*/
function bareTopNetTabLines(net, cols, opts) {
const oopts = opts && typeof opts === 'object' ? opts : {}
const adaptiveMax = cols < 90 ? 256 : cols < 120 ? 384 : 512
const maxTotal = Math.max(8, (oopts.maxLines | 0) || adaptiveMax)
const filt = String(oopts.filter || '')
.trim()
.toLowerCase()
const wide = oopts.wideTwoCol === true && cols >= 100
if (!net || typeof net !== 'object') return [' N/A']
const o = /** @type {Record<string, unknown>} */ (net)
/** @type {string[]} */
const lines = []
function pushFiltered(s) {
if (filt && !String(s).toLowerCase().includes(filt)) return
lines.push(s)
}
function pushSection(title) {
pushFiltered('')
pushFiltered(' --- ' + title + ' ---')
}
if (Array.isArray(o.interfaces)) {
pushSection('interfaces (rx+tx)')
const arr = o.interfaces.slice().sort((a, b) => {
const ta =
a && typeof a === 'object'
? /** @type {Record<string, unknown>} */ (a)
: null
const tb =
b && typeof b === 'object'
? /** @type {Record<string, unknown>} */ (b)
: null
const sa =
(Number(ta && ta.rxBytes) || 0) + (Number(ta && ta.txBytes) || 0)
const sb =
(Number(tb && tb.rxBytes) || 0) + (Number(tb && tb.txBytes) || 0)
return sb - sa
})
const w = Math.max(40, cols - 4)
for (const iface of arr.slice(0, 32)) {
if (!iface || typeof iface !== 'object') continue
const i = /** @type {Record<string, unknown>} */ (iface)
const nm = String(i.name ?? i.if ?? '?')
const rxB = i.rxBytes ?? i.rx
const txB = i.txBytes ?? i.tx
const rxS =
rxB != null && rxB !== '' && Number.isFinite(Number(rxB))
? bareTopNetFormatBytes(rxB)
: String(rxB ?? '\u2014')
const txS =
txB != null && txB !== '' && Number.isFinite(Number(txB))
? bareTopNetFormatBytes(txB)
: String(txB ?? '\u2014')
const extra = Object.keys(i)
.filter((k) => !['name', 'if', 'rxBytes', 'txBytes', 'rx', 'tx'].includes(k))
.slice(0, 4)
.map((k) => {
const v = i[k]
return (
k +
'=' +
(v != null && typeof v !== 'object'
? String(v)
: bareTopJsonSnippet(v, 36))
)
})
.join(' ')
pushFiltered(
' ' +
bareTopTruncateCell(nm, 16, true) +
' rx=' +
rxS +
' tx=' +
txS +
' ' +
bareTopTruncateCell(extra, w - 24, false)
)
}
if (arr.length > 32) {
let remRx = 0
let remTx = 0
for (const iface of arr.slice(32)) {
if (!iface || typeof iface !== 'object') continue
const i = /** @type {Record<string, unknown>} */ (iface)
remRx += Number(i.rxBytes ?? i.rx) || 0
remTx += Number(i.txBytes ?? i.tx) || 0
}
pushFiltered(
' (+ ' +
(arr.length - 32) +
' more) rx=' +
bareTopNetFormatBytes(remRx) +
' tx=' +
bareTopNetFormatBytes(remTx)
)
}
}
const sectionKeys = new Set([
'interfaces',
'replicationQueue',
'peerFirewallStats',
'bsdSocketGuestBridge',
'transport',
'udxTuning',
'hyperswarmTuning',
'peerFirewallE2e',
'stagingSlot',
'snapshotHints'
])
pushSection('summary')
const ordered = bareTopNetOrderedTopKeys(o)
for (const k of ordered) {
if (sectionKeys.has(k)) continue
const v = o[k]
if (v != null && typeof v === 'object') continue
pushFiltered(
' ' +
k +
': ' +
bareTopTruncateCell(bareTopFormatScalarTerminal(v, Math.max(24, cols - 8)), Math.max(20, cols - 6), false)
)
}
if (o.replicationQueue != null) {
pushSection('replicationQueue')
for (const ln of bareTopNetReplicationQueueLines(o.replicationQueue, cols)) pushFiltered(ln)
}
if (o.peerFirewallStats != null) {
pushSection('peerFirewallStats')
for (const ln of bareTopNetPeerFirewallLines(o.peerFirewallStats, cols)) pushFiltered(ln)
}
if (o.bsdSocketGuestBridge != null) {
pushSection('bsdSocketGuestBridge')
for (const ln of bareTopNetBsdBridgeLines(o.bsdSocketGuestBridge, cols)) pushFiltered(ln)
}
const tun = ['transport', 'udxTuning', 'hyperswarmTuning', 'peerFirewallE2e']
for (const tk of tun) {
if (o[tk] == null) continue
pushSection(tk)
const v = o[tk]
if (v != null && typeof v === 'object') {
const jo = /** @type {Record<string, unknown>} */ (v)
const keys = Object.keys(jo).slice(0, 24)
for (const kk of keys) {
const vv = jo[kk]
pushFiltered(
' ' +
kk +
': ' +
bareTopFormatScalarTerminal(vv, Math.max(16, cols - 10))
)
}
} else pushFiltered(' ' + String(v))
}
for (const ek of ['stagingSlot', 'snapshotHints']) {
if (o[ek] == null) continue
pushSection(ek)
const v = o[ek]
if (v != null && typeof v === 'object') {
const jo = /** @type {Record<string, unknown>} */ (v)
for (const kk of Object.keys(jo).slice(0, 20)) {
const vv = jo[kk]
pushFiltered(
' ' +
kk +
': ' +
bareTopFormatScalarTerminal(vv, Math.max(12, cols - 12))
)
}
}
}
if (wide && lines.length > 6) {
/** @type {string[]} */
const merged = []
for (let i = 0; i < lines.length; i += 2) {
const a = lines[i] || ''
const b = lines[i + 1] || ''
const half = Math.floor(cols / 2) - 1
merged.push(
bareTopTruncateCell(a, half, false) +
' | ' +
bareTopTruncateCell(b, half, false)
)
}
lines.length = 0
lines.push(...merged)
}
if (lines.length > maxTotal) {
const head = lines.slice(0, maxTotal - 1)
head.push(' \u2026 (truncated, ' + (lines.length - maxTotal + 1) + ' more lines)')
return head
}
return lines.length ? lines : [' (empty net summary)']
}
function bareTopNetworkDeepDiveLines(extra, cols) {
/** @type {string[]} */
const out = []
const rs =
extra && extra.routeSummary && typeof extra.routeSummary === 'object'
? /** @type {Record<string, unknown>} */ (extra.routeSummary)
: null
if (rs) {
const direct = Number(rs.directCount ?? rs.direct ?? 0) || 0
const relay = Number(rs.relayCount ?? rs.relay ?? 0) || 0
const total = direct + relay
const ratio = total > 0 ? Math.round((direct / total) * 100) : 0
out.push(
' route direct=' +
direct +
' relay=' +
relay +
' directRatio=' +
ratio +
'%'
)
}
const hs =
extra && extra.holepunchSummary && typeof extra.holepunchSummary === 'object'
? /** @type {Record<string, unknown>} */ (extra.holepunchSummary)
: null
if (hs) {
const keys = Object.keys(hs).slice(0, 4)
const bits = keys.map((k) => k + '=' + bareTopFormatScalarTerminal(hs[k], 18))
if (bits.length) out.push(' holepunch ' + bits.join(' '))
}
const sd =
extra && extra.swarmDoctor && typeof extra.swarmDoctor === 'object'
? /** @type {Record<string, unknown>} */ (extra.swarmDoctor)
: null
if (sd) {
const verdict = String(sd.verdict || sd.status || 'unknown')
const rem = Array.isArray(sd.remediation) ? sd.remediation[0] : sd.hint
out.push(
' doctor verdict=' +
verdict +
(rem ? ' hint=' + bareTopTruncateCell(String(rem), Math.max(12, cols - 36), true) : '')
)
}
return out
}
function bareTopPeerDetailsLines(extra, cols) {
const pd =
extra && extra.peerDetails && typeof extra.peerDetails === 'object'
? /** @type {Record<string, unknown>} */ (extra.peerDetails)
: null
if (!pd || !Array.isArray(pd.peers)) return []
/** @type {string[]} */
const out = []
for (const p of pd.peers.slice(0, 12)) {
if (!p || typeof p !== 'object') continue
const r = /** @type {Record<string, unknown>} */ (p)
const key = String(r.remotePublicKey || r.peerId || '?')
const state = String(r.state || 'connected')
const ep =
r.endpoint && typeof r.endpoint === 'object'
? /** @type {Record<string, unknown>} */ (r.endpoint)
: null
const addr = String((ep && ep.address) || r.remoteAddress || '?')
const port = String((ep && ep.port) || r.remotePort || '?')
const os =
r.peerOs && typeof r.peerOs === 'object'
? String((/** @type {Record<string, unknown>} */ (r.peerOs)).osHint || 'unknown')
: 'unknown'
out.push(' peer ' + bareTopTruncateCell(key, Math.max(12, cols - 36), false))
out.push(' state=' + state + ' endpoint=' + addr + ':' + port + ' os=' + os)
}
return out
}
function bareTopDhtScanPostureLines(extra) {
const ds =
extra && extra.dhtScan && typeof extra.dhtScan === 'object'
? /** @type {Record<string, unknown>} */ (extra.dhtScan)
: null
if (!ds) return []
const fire = ds.firewalled
const boot = ds.bootstrapReachable ?? ds.bootstrap
const rnd = ds.randomizedEndpoints ?? ds.randomized
return [
' dht scan firewalled=' +
String(fire == null ? 'n/a' : fire) +
' bootstrap=' +
String(boot == null ? 'n/a' : boot) +
' randomized=' +
String(rnd == null ? 'n/a' : rnd)
]
}
function bareTopMeshdropLines(extra) {
const md =
extra && extra.meshdrop && typeof extra.meshdrop === 'object'
? /** @type {Record<string, unknown>} */ (extra.meshdrop)
: null
if (!md) return []
const rx = Number(md.rxTotal ?? md.rx ?? md.rxEnvelopes) || 0
const tx = Number(md.txTotal ?? md.tx ?? md.txEnvelopes) || 0
return [' meshdrop rx=' + rx + ' tx=' + tx]
}
function bareTopPromHeadlineLines(promText) {
const t = String(promText || '')
if (!t.trim()) return []
const keys = [
'bare_os_kernel_counters',
'bare_os_protomux',
'bare_os_replication',
'bare_os_swarm'
]
/** @type {string[]} */
const out = []
for (const line of t.split('\n')) {
const ln = line.trim()
if (!ln || ln.charAt(0) === '#') continue
for (const k of keys) {
if (ln.startsWith(k)) {
out.push(' ' + ln)
break
}
}
if (out.length >= 12) break
}
return out
}
function bareTopDelegateRateBucketLines(o, cols) {
if (!o || typeof o !== 'object') return []
const rec = /** @type {Record<string, unknown>} */ (o)
const keys = Object.keys(rec).sort()
if (!keys.length) return []
/** @type {string[]} */
const out = []
const w = Math.max(40, Math.min(cols - 2, cols))
for (const k of keys) {
const v = rec[k]
if (Array.isArray(v)) {
const nums = v.map((x) => String(x)).join(' ')
out.push(
' ' +
bareTopTruncateCell(k, Math.min(20, Math.floor(w * 0.35)), true).padEnd(20) +
' ' +
bareTopTruncateCell(nums, w - 24, false)
)
} else if (v != null && typeof v === 'object') {
out.push(
' ' +
k +
': ' +
bareTopJsonSnippet(v, Math.min(120, w - k.length - 4))
)
} else {
out.push(' ' + k + ': ' + String(v))
}
}
return out
}
/**
* Kernel counter keys emitted by the booter (inventory for dashboards):
* initd.unit_failed_final, vfs.readfile.samples, vfs.replication_warm_full_invalidate,
* vfs.warm_read_cache_*, security.key_handle_*, audit.append*, operator.corestore_snapshot_hint,
* vfs.hyperblobs_dedup_* — see bareOsKernelMetricInc call sites in packages/bare-os-booter.
* @param {unknown} counters
* @param {unknown} prev
* @param {boolean} deltaMode
* @param {number} topN
* @param {number} colW
*/
function bareTopKernelCounterLines(counters, prev, deltaMode, topN, colW) {
if (!counters || typeof counters !== 'object') return []
const o = /** @type {Record<string, number>} */ (counters)
const po =
prev && typeof prev === 'object'
? /** @type {Record<string, number>} */ (prev)
: null
const pairs = Object.keys(o)
.map((k) => ({ k, v: Number(o[k]) || 0 }))
.sort((a, b) => b.v - a.v || a.k.localeCompare(b.k))
const lim = Math.min(Math.max(1, topN | 0), pairs.length)
/** @type {string[]} */
const out = []
const wn = Math.max(6, colW | 0)
for (let i = 0; i < lim; i++) {
const { k, v } = pairs[i]
let suf = ''
if (deltaMode && po && Object.prototype.hasOwnProperty.call(po, k)) {
const d = v - (Number(po[k]) || 0)
suf = ' (d ' + (d >= 0 ? '+' : '') + d + ')'
}
const kt = bareTopTruncateCell(k, wn - 1, true)
const kPad = kt + ' '.repeat(Math.max(0, wn - kt.length))
out.push(' ' + kPad + ' ' + String(v) + suf)
}
if (pairs.length > lim) out.push(' … +' + (pairs.length - lim) + ' counters')
return out
}
/**
* @param {unknown} w
*/
function bareTopWarmReadCacheSummaryLines(w) {
if (!w || typeof w !== 'object') return []
const o = /** @type {Record<string, unknown>} */ (w)
const parts = []
for (const key of ['entries', 'bytes', 'hits', 'misses', 'evictions']) {
if (o[key] != null) parts.push(key + '=' + String(o[key]))
}
if (!parts.length) {
const keys = Object.keys(o).slice(0, 8)
for (const k of keys) {
const v = o[k]
if (v != null && typeof v !== 'object') parts.push(k + '=' + String(v))
}
}
if (!parts.length) return []
return [' ' + parts.join(' ')]
}
/**
* @param {unknown} ipc
* @param {number} maxLines
*/
function bareTopIpcTelemetrySummaryLines(ipc, maxLines) {
if (!ipc || typeof ipc !== 'object') return []
const o = /** @type {Record<string, unknown>} */ (ipc)
/** @type {string[]} */
const lines = []
for (const k of Object.keys(o).slice(0, 24)) {
const v = o[k]
if (v != null && typeof v !== 'object') {
lines.push(' ' + k + ': ' + String(v))
} else if (v && typeof v === 'object' && !Array.isArray(v)) {
const sub = /** @type {Record<string, unknown>} */ (v)
const inner = Object.keys(sub)
.slice(0, 6)
.map(
(sk) =>
sk +
'=' +
(sub[sk] != null && typeof sub[sk] !== 'object'
? String(sub[sk])
: bareTopJsonSnippet(sub[sk], 24))
)
.join(' ')
lines.push(' ' + k + ': ' + bareTopTruncateCell(inner, 72, true))
}
if (lines.length >= maxLines) break
}
if (lines.length >= maxLines && Object.keys(o).length > maxLines)
lines.push(' … (truncated)')
return lines
}
/**
* @param {unknown} rep
* @param {string} na
*/
function bareTopReplicationOverviewLines(rep, na) {
if (!rep || typeof rep !== 'object') return []
const o = /** @type {Record<string, unknown>} */ (rep)
/** @type {string[]} */
const lines = []
const sys = o.systemCoreLength
const per = o.personalCoreLength
const aux = o.auxiliaryDriveCount
const pc = o.peerCount
if (typeof sys === 'number') lines.push(' sysCoreLen ' + sys)
if (typeof per === 'number') lines.push(' perCoreLen ' + per)
if (typeof aux === 'number') lines.push(' auxDrives ' + aux)
if (typeof pc === 'number') lines.push(' peerCount ' + pc)
const sh = o.stallHint
if (sh != null && String(sh).trim()) {
lines.push(' stallHint ' + String(sh))
const sl = String(sh).trim().toLowerCase()
if (sl === 'no_peers' || sl === 'length_unavailable' || sl === 'ok')
lines.push(
' (hint is operational — health score treats these as non-fault)'
)
}
if (!lines.length) lines.push(' ' + na)
return lines
}
/**
* @param {unknown} cold
* @param {unknown} stdlib
* @param {unknown} tel
*/
function bareTopBootBudgetLines(cold, stdlib, tel) {
/** @type {string[]} */
const lines = []
const c = cold && typeof cold === 'object' ? /** @type {Record<string, unknown>} */ (cold) : null
const s = stdlib && typeof stdlib === 'object' ? /** @type {Record<string, unknown>} */ (stdlib) : null
if (c) {
const ex = c.exceeded === true
lines.push(
' coldBoot exceeded=' +
(ex ? 'yes' : 'no') +
' wall=' +
String(c.wallMs ?? '—') +
' limit=' +
String(c.limitMs ?? '—')
)
}
if (s) {
const ex = s.exceeded === true
lines.push(
' bareStdlib exceeded=' +
(ex ? 'yes' : 'no') +
' wall=' +
String(s.wallMs ?? '—') +
' limit=' +
String(s.limitMs ?? '—')
)
}
if (tel && typeof tel === 'object') {
const t = /** @type {Record<string, unknown>} */ (tel)
lines.push(
' policy strict=' +
String(!!t.strict) +
' bootPerf=' +
String(t.bootPerfJsonPath || '/run/bare-os/boot-perf.json')
)
}
return lines
}
/**
* @param {unknown} sl
*/
function bareTopSwarmLifecycleLine(sl) {
if (!sl || typeof sl !== 'object') return ''
const o = /** @type {Record<string, unknown>} */ (sl)
const parts = []
for (const k of Object.keys(o).slice(0, 12)) {
const v = o[k]
if (v != null && typeof v !== 'object') parts.push(k + '=' + v)
}
if (!parts.length) return ''
return ' swarm ' + parts.join(' ') + ' (tab: operator)'
}
/**
* @param {unknown} pt
*/
function bareTopProcessStateHistogramLines(pt) {
const rows = bareTopProcessRowsFromTable(pt)
/** @type {Record<string, number>} */
const h = {}
for (const r of rows) {
const st = String(r.state || '?')
h[st] = (h[st] || 0) + 1
}
const parts = Object.keys(h)
.sort()
.map((k) => k + ':' + h[k])
if (!parts.length) return []
return [' states ' + parts.join(' ')]
}
/**
* @param {unknown} ir
*/
function bareTopInitdReadinessSummaryLines(ir) {
if (!ir || typeof ir !== 'object') return []
const o = /** @type {Record<string, unknown>} */ (ir)
const units = Array.isArray(o.units) ? o.units : []
let active = 0
let starting = 0
let failed = 0
let other = 0
for (const u of units) {
if (!u || typeof u !== 'object') continue
const ph = String(/** @type {Record<string, unknown>} */ (u).phase || '')
if (ph === 'active') active++
else if (ph === 'starting') starting++
else if (ph === 'failed') failed++
else other++
}
if (!units.length) return []
return [
' initd units=' +
units.length +
' active=' +
active +
' starting=' +
starting +
' failed=' +
failed +
(other ? ' other=' + other : '')
]
}
/**
* @param {unknown} m metrics live
* @param {number} nowMs
* @param {string} na
*/
function bareTopMetaCoalesceLine(m, nowMs, na) {
if (!m || typeof m !== 'object') return ''
const o = /** @type {Record<string, unknown>} */ (m)
const co = o.coalesceMs
const at = o.atMs
let age = ''
if (typeof at === 'number' && Number.isFinite(at)) {
age = ' age=' + Math.max(0, Math.floor(nowMs - at)) + 'ms'
}
return (
' metrics coalesceMs=' +
(typeof co === 'number' ? co : na) +
' atMs=' +
(typeof at === 'number' ? at : na) +
age
)
}
/**
* @param {unknown} wbh
*/
function bareTopWorkerBudgetCompactLine(wbh) {
if (!wbh || typeof wbh !== 'object') return ''
const o = /** @type {Record<string, unknown>} */ (wbh)
const parts = []
if (o.wallMsMax != null) parts.push('wallMax=' + String(o.wallMsMax))
if (o.cpuMsMax != null) parts.push('cpuMax=' + String(o.cpuMsMax))
if (!parts.length) return ''
return ' workerBudget ' + parts.join(' ')
}
/**
* @param {unknown} cs collaboration session object
*/
function bareTopProtomuxCollabLine(cs) {
if (!cs || typeof cs !== 'object') return ''
const o = /** @type {Record<string, unknown>} */ (cs)
const rx = o.protomuxAppChannelRxTotal
const cap = o.protomuxCapChannelRxTotal
const parts = []
if (typeof rx === 'number') parts.push('appRx=' + rx)
if (typeof cap === 'number') parts.push('capRx=' + cap)
if (!parts.length) return ''
return ' protomux ' + parts.join(' ')
}
/**
* @param {unknown} pt
*/
function bareTopLogicalFdAggregateLine(pt) {
const rows = bareTopProcessRowsFromTable(pt)
let n = 0
for (const r of rows) {
const ft = r.fdTable
if (Array.isArray(ft)) n += ft.length
}
if (!n) return ''
return ' logicalFds rows=' + n + ' (fdTable entries)'
}
/**
* @param {unknown} hostStats
*/
function bareTopHostStatsSummaryLine(hostStats) {
if (!hostStats || typeof hostStats !== 'object') return ''
const o = /** @type {Record<string, unknown>} */ (hostStats)
const pick = [
'cpuBusyPct',
'cpuPct',
'memUsedPct',
'rssBytes',
'hostname',
'eventLoopLagMs',
'loopLagMs',
'lagMs'
]
const parts = []
for (const k of pick) {
if (o[k] != null && typeof o[k] !== 'object')
parts.push(k + '=' + String(o[k]))
}
if (!parts.length) return ''
return ' host ' + parts.join(' ') + ' (detail: host tab)'
}
/**
* @param {unknown} resources
* @param {number} maxKeys
*/
function bareTopResourcesSummaryLines(resources, maxKeys) {
if (!resources || typeof resources !== 'object') return []
const o = /** @type {Record<string, unknown>} */ (resources)
const keys = Object.keys(o).slice(0, Math.max(1, maxKeys | 0))
/** @type {string[]} */
const lines = []
for (const k of keys) {
const v = o[k]
if (v != null && typeof v !== 'object')
lines.push(' ' + k + ': ' + String(v).slice(0, 120))
}
if (Object.keys(o).length > keys.length) lines.push(' … +' + (Object.keys(o).length - keys.length) + ' keys (full: diagnostics)')
return lines
}
/**
* @param {number} peersMl peers from metrics_live
* @param {unknown} repLive replicationLive object
*/
function bareTopPeerMismatchWarningLine(peersMl, repLive) {
if (!repLive || typeof repLive !== 'object') return ''
const o = /** @type {Record<string, unknown>} */ (repLive)
const pc = o.peerCount
if (typeof pc !== 'number' || !Number.isFinite(peersMl)) return ''
if (Math.abs(pc - peersMl) > 2)
return ' warn peerCount mismatch metrics peers=' + peersMl + ' replication.peerCount=' + pc
return ''
}
/**
* @param {unknown} extraIpc from /proc/bare_os/ipc_backpressure.json
*/
function bareTopIpcBackpressureProcLine(extraIpc) {
if (!extraIpc || typeof extraIpc !== 'object') return ''
const o = /** @type {Record<string, unknown>} */ (extraIpc)
const parts = []
for (const k of Object.keys(o).slice(0, 14)) {
const v = o[k]
if (typeof v === 'number' && v !== 0)
parts.push(k + '=' + bareTopFormatIntGrouped(v))
else if (v === true) parts.push(k)
}
if (!parts.length) return ''
return ' ipcBackpressure(proc) ' + parts.join(' ')
}
/**
* @param {unknown} syscallsParsed
*/
function bareTopSyscallsOverviewLines(syscallsParsed) {
if (!syscallsParsed || typeof syscallsParsed !== 'object') return []
const o = /** @type {Record<string, unknown>} */ (syscallsParsed)
const ops = o.ops
const n = Array.isArray(ops) ? ops.length : 0
return [
' syscalls schemaVersion=' +
String(o.schemaVersion ?? '?') +
' stockOps~' +
n
]
}
/**
* @param {string} diskRaw
*/
function bareTopDiskstatsOverviewLines(diskRaw) {
const s = String(diskRaw || '').trim()
if (!s) return []
const first = s.split('\n')[0] || ''
if (first.length < 6) return []
return [' diskstats ' + bareTopTruncateCell(first, 110, true)]
}
/**
* @param {unknown} dr delegate_red.json
*/
function bareTopDelegateRedOverviewLines(dr) {
if (!dr || typeof dr !== 'object') return []
if (!Object.keys(dr).length) return []
return [
' delegate_red ' +
bareTopTruncateCell(bareTopJsonSnippet(dr, 220), 118, true)
]
}
/**
* @param {unknown} sp security_posture.json
*/
function bareTopSecurityPostureOverviewLines(sp) {
if (!sp || typeof sp !== 'object') return []
const o = /** @type {Record<string, unknown>} */ (sp)
const parts = []
if (typeof o.schema === 'number') parts.push('schema=' + o.schema)
if (o.bootPolicyStrict != null) parts.push('bootStrict=' + String(o.bootPolicyStrict))
if (o.bootPolicyMerged != null) parts.push('bootPol=' + String(o.bootPolicyMerged))
if (o.ctxApiVersion != null) parts.push('ctxApi=' + String(o.ctxApiVersion).slice(0, 20))
return parts.length ? [' security_posture ' + parts.join(' ')] : []
}
/**
* @param {unknown} bb boot_budget_summary.json
*/
function bareTopBootBudgetSummaryOverviewLines(bb) {
if (!bb || typeof bb !== 'object') return []
const o = /** @type {Record<string, unknown>} */ (bb)
const parts = []
const crit = o.criticalPathMs ?? o.criticalPathWallMs ?? o.totalWallMs
if (typeof crit === 'number') parts.push('critical~' + bareTopFormatDurationMs(crit))
const top = o.slowestUnit ?? o.criticalUnit ?? o.topUnit ?? o.bottleneck
if (top != null) parts.push('top=' + String(top).slice(0, 28))
if (o.exceeded === true) parts.push('EXCEEDED')
return parts.length ? [' boot_budget_summary ' + parts.join(' ')] : []
}
/**
* @param {unknown} ph peer_health.json
*/
function bareTopWorstPeerOverviewLines(ph) {
if (!ph || typeof ph !== 'object') return []
const peers = /** @type {Record<string, unknown>} */ (ph).peers
if (!Array.isArray(peers) || !peers.length) return []
let worst = /** @type {Record<string, unknown> | null} */ (null)
let worstScore = -1
for (const p of peers) {
if (!p || typeof p !== 'object') continue
const r = /** @type {Record<string, unknown>} */ (p)
const err = r.error ?? r.lastError ?? r.status
const lat = Number(r.rttMs ?? r.latencyMs ?? r.rtt ?? 0)
const sc =
err != null && String(err).trim() ? 1e12 : Number.isFinite(lat) ? lat : 0
if (sc > worstScore) {
worstScore = sc
worst = r
}
}
if (!worst) return []
const id = String(
worst.publicKeyHex?.slice?.(0, 14) ||
worst.publicKey?.slice?.(0, 14) ||
worst.peerId ||
worst.id ||
'?'
)
const tail = bareTopJsonSnippet(worst, 72)
return [' worstPeer ' + id + ' ' + tail]
}
/**
* @param {unknown} ext extensions.json
*/
function bareTopExtensionsOverviewLines(ext) {
if (!ext || typeof ext !== 'object') return []
const root = /** @type {Record<string, unknown>} */ (ext)
const list = root.extensions ?? root.names ?? root.list
const names = Array.isArray(list)
? list
.map((x) => {
if (x && typeof x === 'object')
return String(
/** @type {Record<string, unknown>} */ (x).name ??
/** @type {Record<string, unknown>} */ (x).id ??
''
)
return String(x)
})
.filter(Boolean)
: []
const head = names.slice(0, 5).join(', ')
return [
' extensions count=' +
names.length +
(head ? ' e.g. ' + bareTopTruncateCell(head, 56, true) : '')
]
}
/**
* @param {unknown} cj capabilities.json
* @param {unknown} cn capabilities node JSON
*/
function bareTopCapabilitiesDiffOverviewLines(cj, cn) {
if (!cj || typeof cj !== 'object' || !cn || typeof cn !== 'object') return []
const a = /** @type {Record<string, unknown>} */ (cj)
const b = /** @type {Record<string, unknown>} */ (cn)
const ka = new Set(Object.keys(a))
const kb = new Set(Object.keys(b))
const onlyA = [...ka].filter((k) => !kb.has(k)).slice(0, 8)
const onlyB = [...kb].filter((k) => !ka.has(k)).slice(0, 8)
/** @type {string[]} */
const out = []
if (onlyA.length) out.push(' cap onlyInJson: ' + onlyA.join(', '))
if (onlyB.length) out.push(' cap onlyInNode: ' + onlyB.join(', '))
if (!out.length)
out.push(' cap seed JSON vs /capabilities: same top-level keys (sampled)')
return out
}
/**
* @param {unknown} gitDel
* @param {unknown} gitLfs
* @param {unknown} prevDel
* @param {unknown} prevLfs
*/
function bareTopGitStatsDeltaOverviewLines(gitDel, gitLfs, prevDel, prevLfs) {
function pickNum(o, keys) {
if (!o || typeof o !== 'object') return null
const r = /** @type {Record<string, unknown>} */ (o)
for (const k of keys) {
const v = r[k]
if (typeof v === 'number' && Number.isFinite(v)) return v
}
return null
}
/** @type {string[]} */
const out = []
const c1 = pickNum(gitDel, ['delegatesStarted', 'total', 'invocations'])
const p1 = pickNum(prevDel, ['delegatesStarted', 'total', 'invocations'])
if (c1 != null && p1 != null) out.push(' gitDelegate d=' + (c1 - p1))
const c2 = pickNum(gitLfs, ['pointersResolved', 'resolved', 'total'])
const p2 = pickNum(prevLfs, ['pointersResolved', 'resolved', 'total'])
if (c2 != null && p2 != null) out.push(' gitLfs d=' + (c2 - p2))
return out
}
/**
* @param {unknown} wb worker_budget.json
* @param {unknown} sb sandbox_profile.json
*/
function bareTopWorkerSandboxOverviewLines(wb, sb) {
const parts = []
if (wb && typeof wb === 'object') {
const o = /** @type {Record<string, unknown>} */ (wb)
const wm = Number(o.wallMsMax)
const wu = Number(o.wallMsUsed ?? o.wallMsTotal ?? o.usedWallMs)
if (Number.isFinite(wm) && wm > 0 && Number.isFinite(wu)) {
const pct = Math.min(100, Math.round((wu / wm) * 100))
if (pct >= 85) parts.push('workerBudget~' + pct + '%')
}
}
if (sb && typeof sb === 'object') {
const o = /** @type {Record<string, unknown>} */ (sb)
if (o.denied === true || o.violationCount === true || o.violations)
parts.push('sandbox:check')
}
return parts.length ? [' worker/sandbox ' + parts.join(' ')] : []
}
/** Default overview section ids in render order */
var BARE_TOP_OVERVIEW_DEFAULT_SECTIONS = [
'session',
'pipeline',
'delegates',
'replication',
'nethealth',
'kernel',
'warm',
'ipc',
'boot',
'swarm',
'prochist',
'offenders',
'microtrends',
'protomux',
'meta',
'worker',
'initd',
'fdagg',
'delegate_rates',
'fairness',
'subprocess',
'host',
'limits',
'p2p',
'diskio',
'syscallsum',
'delegate_red',
'security',
'bootsum',
'badpeer',
'capdiff',
'extsum',
'gitcounters',
'resources',
'readerr'
]
/**
* @param {string} raw
* @param {boolean} compact
* @returns {Set<string> | null} null = use default list
*/
function bareTopOverviewSectionSet(raw, compact) {
const s = String(raw || '').trim()
if (!s) {
const base = BARE_TOP_OVERVIEW_DEFAULT_SECTIONS.slice()
if (compact) {
const drop = new Set([
'fairness',
'subprocess',
'host',
'resources',
'limits',
'p2p',
'diskio',
'syscallsum',
'security',
'bootsum',
'capdiff',
'gitcounters',
'extsum'
])
return new Set(base.filter((x) => !drop.has(x)))
}
return new Set(base)
}
const parts = s.split(/[,;]+/).map((x) => x.trim().toLowerCase()).filter(Boolean)
return new Set(parts)
}
/**
* @typedef {{
* cols: number,
* na: string,
* compact: boolean,
* sectionFilter: string,
* deltaMode: boolean,
* prevMetrics: Record<string, unknown> | null,
* nowMs: number,
* asciiSep: boolean,
* flattenCap: ((v: unknown, maxLines: number, maxKeys: number) => string[]) | null,
* ringProto: number[],
* microTrendCpu?: number[],
* microTrendMem?: number[],
* microTrendNet?: number[],
* protomuxSpark: boolean,
* sparkW: number,
* sparkAscii: boolean,
* logSpark: boolean,
* braille: boolean,
* healthDetail: boolean,
* healthBreakdown: string,
* splitLeftCol: number,
* splitMiniProc: boolean,
* layoutVersion: string,
* sectionsRaw?: string,
* sessionWallRing?: number[],
* prevSnap?: Record<string, unknown> | null
* }} BareTopOverviewOpts
*/
/**
* @param {Record<string, unknown>} snap
* @param {BareTopOverviewOpts} opts
* @returns {{ lines: string[], activeSections: string[], sectionRawLineIndex: Record<string, number> }}
*/
function bareTopOverviewLines(snap, opts) {
const na = opts.na || 'N/A'
const cols = Math.max(40, opts.cols | 0)
const fc = opts.flattenCap
const sectionSet =
opts.sectionsRaw != null && String(opts.sectionsRaw).trim()
? bareTopOverviewSectionSet(String(opts.sectionsRaw), false)
: bareTopOverviewSectionSet('', opts.compact)
const filter = String(opts.sectionFilter || '').trim().toLowerCase()
/** @type {string[]} */
const lines = []
/** @type {string[]} */
const active = []
/** @type {Record<string, number>} */
const sectionRawLineIndex = {}
const m = snap.metricsLive
const sess =
m && typeof m.session === 'object' && m.session
? /** @type {Record<string, unknown>} */ (m.session)
: {}
function want(id) {
if (!sectionSet.has(id)) return false
if (filter && !id.includes(filter) && !bareTopSectionTitleFor(id).toLowerCase().includes(filter))
return false
return true
}
function pushSec(title, id, bodyLines) {
if (!want(id)) return
sectionRawLineIndex[id] = lines.length
active.push(id)
lines.push('')
lines.push(bareTopSectionSeparator(title, cols, opts.asciiSep))
for (const ln of bodyLines) lines.push(bareTopSanitizeVisible(ln))
}
const ec = Number(sess.execLineCount) || 0
const pb = Number(sess.pipelineBytesTotal) || 0
const wm = Number(sess.execLineWallMsTotal) || 0
if (want('session')) {
sectionRawLineIndex.session = lines.length
active.push('session')
lines.push('')
lines.push(bareTopSectionSeparator('Session', cols, opts.asciiSep))
lines.push(
bareTopSanitizeVisible(
' execLineCount=' + (sess.execLineCount ?? na) + ' pipelineBytesTotal=' + (sess.pipelineBytesTotal ?? na)
)
)
lines.push(
bareTopSanitizeVisible(' execLineWallMsTotal=' + (sess.execLineWallMsTotal ?? na))
)
const ringW = opts.sessionWallRing
if (ringW && ringW.length && opts.sparkW > 0) {
const sp = bareTopSparklineOverview(
ringW,
Math.min(32, opts.sparkW),
opts.sparkAscii,
opts.logSpark,
opts.braille
)
lines.push(bareTopSanitizeVisible(' execLineWallMsTotal spark ' + sp))
}
}
if (want('pipeline')) {
const pg = bareTopPipelineGaugesFromMetrics(m && m.pipeline, cols)
pushSec('Pipeline limits', 'pipeline', pg ? [pg] : [' ' + na])
}
if (want('delegates')) {
const delI = m && m.delegateInflight
/** @type {string[]} */
const dl = []
if (delI != null && typeof delI === 'object') {
dl.push(...bareTopDelegateInflightTableLines(delI, 20, Math.min(24, Math.floor(cols * 0.35))))
} else dl.push(' ' + na)
pushSec('Delegates (inflight)', 'delegates', dl)
}
const repLive = m && m.replicationLive
if (want('replication')) {
pushSec('Replication live', 'replication', bareTopReplicationOverviewLines(repLive, na))
}
if (want('nethealth')) {
const nl = bareTopNetHealthOverviewLines(snap.netSummary, m)
if (nl.length) pushSec('Network summary', 'nethealth', nl)
}
if (want('kernel')) {
const prevK =
opts.prevMetrics && opts.prevMetrics.kernelCounters
? opts.prevMetrics.kernelCounters
: null
const kTop = opts.compact ? 12 : 22
const kl = bareTopKernelCounterLines(
m && m.kernelCounters,
prevK,
opts.deltaMode,
kTop,
Math.min(28, Math.floor(cols * 0.38))
)
pushSec('Kernel counters', 'kernel', kl.length ? kl : [' ' + na])
}
if (want('warm')) {
const wl = bareTopWarmReadCacheSummaryLines(m && m.warmReadCache)
pushSec('Warm read cache', 'warm', wl.length ? wl : [' ' + na])
}
if (want('ipc')) {
/** @type {string[]} */
const ibody = bareTopIpcTelemetrySummaryLines(m && m.ipcTelemetry, 8).slice()
const ipL = bareTopIpcBackpressureProcLine(
snap.extra && snap.extra.ipcBackpressure
)
if (ipL) ibody.push(ipL)
pushSec('IPC telemetry', 'ipc', ibody.length ? ibody : [' ' + na])
}
if (want('boot')) {
const bl = bareTopBootBudgetLines(
m && m.bootBudgetCold,
m && m.bootBudgetBareStdlib,
m && m.bootBudgetTelemetry
)
pushSec('Boot budget', 'boot', bl.length ? bl : [' ' + na])
}
if (want('swarm') && m && m.swarmLifecycle) {
const sl = bareTopSwarmLifecycleLine(m.swarmLifecycle)
pushSec('Swarm lifecycle', 'swarm', sl ? [sl] : [' ' + na])
}
const pt =
(m && m.processTable && typeof m.processTable === 'object'
? m.processTable
: null) ||
(snap.extra &&
snap.extra.processTable &&
typeof snap.extra.processTable === 'object'
? snap.extra.processTable
: null)
if (want('prochist')) {
pushSec('Process states', 'prochist', bareTopProcessStateHistogramLines(pt))
}
if (want('offenders') && pt) {
const rows = bareTopProcessRowsFromTable(pt)
const byCpu = rows
.slice()
.sort(
(a, b) =>
(Number(b.cpuPct ?? b.cpu ?? 0) || 0) - (Number(a.cpuPct ?? a.cpu ?? 0) || 0)
)
.slice(0, 3)
const byRss = rows
.slice()
.sort(
(a, b) =>
(Number(b.rssBytes ?? b.rss ?? 0) || 0) - (Number(a.rssBytes ?? a.rss ?? 0) || 0)
)
.slice(0, 3)
const byIo = rows
.slice()
.sort(
(a, b) =>
(Number(b.ioBytesDelta ?? b.ioBytes ?? 0) || 0) - (Number(a.ioBytesDelta ?? a.ioBytes ?? 0) || 0)
)
.slice(0, 3)
/** @type {string[]} */
const out = []
if (byCpu.length)
out.push(
' cpu ' +
byCpu
.map((r) => String(r.name || r.pid || '?') + ':' + String(Math.round(Number(r.cpuPct ?? r.cpu ?? 0) || 0)) + '%')
.join(' ')
)
if (byRss.length)
out.push(
' rss ' +
byRss
.map((r) => String(r.name || r.pid || '?') + ':' + bareTopNetFormatBytes(Number(r.rssBytes ?? r.rss ?? 0) || 0))
.join(' ')
)
if (byIo.length)
out.push(
' io ' +
byIo
.map((r) => String(r.name || r.pid || '?') + ':' + bareTopNetFormatBytes(Number(r.ioBytesDelta ?? r.ioBytes ?? 0) || 0))
.join(' ')
)
if (out.length) pushSec('Top offenders', 'offenders', out)
}
if (want('microtrends') && opts.sparkW > 0) {
/** @type {string[]} */
const tr = []
if (opts.microTrendCpu && opts.microTrendCpu.length) {
tr.push(
' cpu ' +
bareTopSparklineOverview(
opts.microTrendCpu,
Math.min(28, opts.sparkW),
opts.sparkAscii,
opts.logSpark,
opts.braille
)
)
}
if (opts.microTrendMem && opts.microTrendMem.length) {
tr.push(
' mem ' +
bareTopSparklineOverview(
opts.microTrendMem,
Math.min(28, opts.sparkW),
opts.sparkAscii,
opts.logSpark,
opts.braille
)
)
}
if (opts.microTrendNet && opts.microTrendNet.length) {
tr.push(
' net ' +
bareTopSparklineOverview(
opts.microTrendNet,
Math.min(28, opts.sparkW),
opts.sparkAscii,
opts.logSpark,
opts.braille
)
)
}
if (tr.length) pushSec('Micro trends', 'microtrends', tr)
}
if (want('protomux')) {
const cs =
repLive &&
typeof repLive === 'object' &&
repLive.collaborationSession &&
typeof repLive.collaborationSession === 'object'
? repLive.collaborationSession
: null
/** @type {string[]} */
const pl = []
const cl = bareTopProtomuxCollabLine(cs)
if (cl) pl.push(cl)
if (opts.protomuxSpark && opts.ringProto && opts.ringProto.length && opts.sparkW > 0) {
const sp = bareTopSparklineOverview(
opts.ringProto,
opts.sparkW,
opts.sparkAscii,
opts.logSpark,
opts.braille
)
pl.push(' appRx spark ' + sp)
}
if (pl.length) pushSec('Protomux / collab', 'protomux', pl)
}
if (want('meta')) {
const ml = bareTopMetaCoalesceLine(m, opts.nowMs, na)
if (ml) pushSec('Refresh meta', 'meta', [ml])
}
if (want('worker')) {
/** @type {string[]} */
const wbod = []
const wl = bareTopWorkerBudgetCompactLine(m && m.workerBudgetHints)
if (wl) wbod.push(wl)
const ws = bareTopWorkerSandboxOverviewLines(
snap.extra && snap.extra.workerBudget,
snap.extra && snap.extra.sandboxProfile
)
for (const x of ws) wbod.push(x)
if (wbod.length) pushSec('Worker budget', 'worker', wbod)
}
if (want('initd')) {
pushSec('Initd readiness', 'initd', bareTopInitdReadinessSummaryLines(m && m.initdReadiness))
}
if (want('fdagg')) {
const fl = bareTopLogicalFdAggregateLine(pt)
if (fl) pushSec('FD summary', 'fdagg', [fl])
}
if (want('delegate_rates') && m && m.delegateRateBuckets != null) {
pushSec('Delegate rate buckets', 'delegate_rates', bareTopDelegateRateBucketLines(m.delegateRateBuckets, cols))
}
if (want('fairness') && snap.fairnessSnapshot && fc) {
const fl = fc(snap.fairnessSnapshot, 14, 32)
const expl = [
' Fairness = delegate / job scheduling hints (not host CPU share).'
]
pushSec('Fairness', 'fairness', expl.concat(fl))
}
if (want('subprocess') && snap.subprocessBridge && fc) {
pushSec('Subprocess bridge', 'subprocess', fc(snap.subprocessBridge, 12, 24))
}
if (want('limits')) {
const ll = bareTopLimitsMergedLines(
/** @type {Record<string, unknown>} */ (snap)
)
if (ll.length) {
ll.push(
' note: quotas = operator pipeline caps; rlimits = per-process limits mirror.'
)
pushSec('Limits (quotas + rlimits)', 'limits', ll)
}
}
if (want('p2p')) {
const pl = bareTopP2PStackLines(/** @type {Record<string, unknown>} */ (snap))
if (pl.length) pushSec('P2P / HDMS / DHT', 'p2p', pl)
}
if (want('diskio') && snap.diskstatsLine) {
const dl = bareTopDiskstatsOverviewLines(String(snap.diskstatsLine))
if (dl.length) pushSec('Disk', 'diskio', dl)
}
if (want('syscallsum')) {
const sy = snap.extra && snap.extra.syscalls
const sl = bareTopSyscallsOverviewLines(
sy && typeof sy === 'object' ? sy : null
)
if (sl.length) pushSec('Syscalls proc', 'syscallsum', sl)
}
if (want('delegate_red')) {
const dr = snap.extra && snap.extra.delegateRed
const dl = bareTopDelegateRedOverviewLines(dr)
if (dl.length) pushSec('Delegate red', 'delegate_red', dl)
}
if (want('security')) {
const sp = snap.extra && snap.extra.securityPosture
const sl = bareTopSecurityPostureOverviewLines(sp)
if (sl.length) pushSec('Security posture', 'security', sl)
}
if (want('bootsum')) {
const bb = snap.extra && snap.extra.bootBudgetSummary
const bl = bareTopBootBudgetSummaryOverviewLines(bb)
if (bl.length) pushSec('Boot budget file', 'bootsum', bl)
}
if (want('badpeer')) {
const ph = snap.extra && snap.extra.peerHealth
const wl = bareTopWorstPeerOverviewLines(ph)
if (wl.length) pushSec('Peer health', 'badpeer', wl)
}
if (want('capdiff')) {
const cj = snap.extra && snap.extra.capabilitiesJson
const cn = snap.extra && snap.extra.capabilitiesNode
const cl = bareTopCapabilitiesDiffOverviewLines(cj, cn)
if (cl.length) pushSec('Capabilities diff', 'capdiff', cl)
}
if (want('extsum')) {
const ex = snap.extra && snap.extra.extensions
const el = bareTopExtensionsOverviewLines(ex)
if (el.length) pushSec('Extensions', 'extsum', el)
}
if (want('gitcounters') && opts.deltaMode && opts.prevSnap) {
const gl = bareTopGitStatsDeltaOverviewLines(
snap.extra && snap.extra.gitDelegateStats,
snap.extra && snap.extra.gitLfsPointerStats,
opts.prevSnap.extra && opts.prevSnap.extra.gitDelegateStats,
opts.prevSnap.extra && opts.prevSnap.extra.gitLfsPointerStats
)
if (gl.length) pushSec('Git stats delta', 'gitcounters', gl)
}
if (want('host') && snap.hostStats) {
const hl = bareTopHostStatsSummaryLine(snap.hostStats)
if (hl) pushSec('Host stats', 'host', [hl])
}
if (want('resources') && snap.resources) {
const full = !opts.compact && fc
if (full) {
pushSec('Resources', 'resources', fc(snap.resources, 20, 40))
} else {
pushSec('Resources', 'resources', bareTopResourcesSummaryLines(snap.resources, 10))
}
}
if (
want('readerr') &&
(snap.readErr ||
(Array.isArray(snap.readErrPaths) && snap.readErrPaths.length))
) {
/** @type {string[]} */
const erl = []
if (snap.readErr) {
const err = String(snap.readErr)
const wrapped = err.split('\n').slice(0, 3)
for (const w of wrapped) erl.push(' warn ' + w)
if (err.split('\n').length > 3) erl.push(' … (truncated)')
}
const paths = Array.isArray(snap.readErrPaths) ? snap.readErrPaths : []
for (const p of paths.slice(0, 16)) {
erl.push(' read fail ' + bareTopSanitizeVisible(String(p)))
}
if (erl.length) pushSec('Read errors', 'readerr', erl)
}
const mismatch = bareTopPeerMismatchWarningLine(Number(m && m.peers) || 0, repLive)
if (mismatch && want('replication')) {
lines.push(bareTopSanitizeVisible(mismatch))
}
if (opts.healthDetail && opts.healthBreakdown) {
sectionRawLineIndex.health_detail = lines.length
lines.push('')
lines.push(bareTopSanitizeVisible(' health detail ' + opts.healthBreakdown))
active.push('health_detail')
}
return { lines, activeSections: active, sectionRawLineIndex }
}
function bareTopSectionTitleFor(id) {
const map = {
session: 'session',
pipeline: 'pipeline',
delegates: 'delegates',
replication: 'replication',
kernel: 'kernel',
warm: 'warm',
ipc: 'ipc',
boot: 'boot',
swarm: 'swarm',
prochist: 'process',
protomux: 'protomux',
meta: 'meta',
worker: 'worker',
initd: 'initd',
initd_phases: 'initd',
fdagg: 'fd',
delegate_rates: 'delegate',
fairness: 'fairness',
subprocess: 'subprocess',
host: 'host',
resources: 'resources',
readerr: 'error',
limits: 'limits',
p2p: 'p2p',
nethealth: 'network',
diskio: 'disk',
syscallsum: 'syscall',
delegate_red: 'delegate',
security: 'security',
bootsum: 'boot',
badpeer: 'peer',
capdiff: 'cap',
extsum: 'ext',
gitcounters: 'git'
}
return map[id] || id
}
/**
* Pipeline gauges string (shared with TUI).
* Duplicates bareTopPipelineGauges from tui when only helpers are tested; TUI keeps full color version.
*/
function bareTopPipelineGaugesFromMetrics(pl, cols) {
if (!pl || typeof pl !== 'object') return ''
const o = /** @type {Record<string, unknown>} */ (pl)
const parts = []
for (const k of Object.keys(o).slice(0, 8)) {
const v = o[k]
if (typeof v === 'number' && Number.isFinite(v)) {
const cap = v > 1000 ? v : 100
const pct = Math.min(100, Math.round((v / cap) * 100))
parts.push(k.slice(0, 10) + '=' + pct + '%')
}
}
return parts.join(' ').slice(0, Math.max(20, cols - 2))
}
/**
* @param {number[]} values
* @param {number} width
* @param {boolean} ascii
* @param {boolean} logScale
* @param {boolean} braille
*/
function bareTopSparklineOverview(values, width, ascii, logScale, braille) {
if (width <= 0) return ''
const slice =
values.length > width ? values.slice(values.length - width) : values.slice()
if (slice.length === 0) return ' '.repeat(width)
const vmap = logScale
? slice.map((v) => Math.log1p(Math.max(0, v)))
: slice.slice()
let min = vmap[0]
let max = vmap[0]
for (let i = 1; i < vmap.length; i++) {
if (vmap[i] < min) min = vmap[i]
if (vmap[i] > max) max = vmap[i]
}
const span = max - min || 1
const uni = '\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588'
const br = '\u2800\u2840\u28c0\u28e0\u28f0\u28f4\u28f6\u28ff'
const asc = ' .:-=+*#'
let out = ''
const pad = width - slice.length
for (let i = 0; i < pad; i++) out += ascii ? ' ' : '\u2581'
for (let i = 0; i < vmap.length; i++) {
const v = vmap[i]
const t = (v - min) / span
let idx = Math.min(7, Math.floor(t * 8))
if (idx < 0) idx = 0
if (ascii) out += asc.charAt(idx)
else if (braille) out += br.charAt(idx)
else out += uni.charAt(idx)
}
return out.slice(0, width)
}