better emebed design
Release rolling / release (push) Successful in 13m50s

This commit is contained in:
Raven Scott
2026-08-13 14:11:01 -04:00
parent 9a810cdf74
commit 58e6e62ee9
10 changed files with 1300 additions and 425 deletions
+397 -122
View File
@@ -502,7 +502,7 @@ function discordPrettyValue(key, val) {
} }
if (typeof val === 'string') { if (typeof val === 'string') {
const t = discordCmdRedact(val) const t = discordCmdRedact(val)
if (/^[0-9a-f]{24,}$/i.test(t)) return t.slice(0, 12) + '…' if (/^[0-9a-f]{24,}$/i.test(t)) return '`' + t.slice(0, 16) + (t.length > 16 ? '…' : '') + '`'
return t.length > 180 ? t.slice(0, 177) + '…' : t return t.length > 180 ? t.slice(0, 177) + '…' : t
} }
if (Array.isArray(val)) { if (Array.isArray(val)) {
@@ -520,36 +520,86 @@ function discordPrettyValue(key, val) {
} }
function discordSkipPrettyKey(k) { function discordSkipPrettyKey(k) {
return /TOKEN|SECRET|PASSWORD|PASSWD|PRIVATE|CREDENTIAL|API_KEY/i.test(k) return /TOKEN|SECRET|PASSWORD|PASSWD|PRIVATE|CREDENTIAL|API_KEY/i.test(k) ||
k === 'note' ||
k === 'schema' ||
k === 'schemaVersion'
}
function discordValueEmpty(val) {
if (val == null) return true
if (val === '') return true
if (val === '—') return true
if (Array.isArray(val) && !val.length) return true
if (typeof val === 'object' && !Array.isArray(val) && !Object.keys(val).length) return true
return false
}
function discordHumanLabel(key) {
const known = {
schemaVersion: 'Schema',
topicHex: 'Topic',
peerCount: 'Peers',
seedHandshakeError: 'Handshake',
seedRole: 'Role',
replicationQueueDepth: 'Queue depth',
replicationQueue: 'Replication',
stagingSlot: 'Staging',
snapshotHints: 'Snapshot',
peerFirewallStats: 'Firewall',
peerFirewallAcceptedTotal: 'Accepted',
peerFirewallRejectedTotal: 'Rejected',
peerFirewallInboundTotal: 'Inbound',
peerFirewallOutboundTotal: 'Outbound',
peerFirewallE2e: 'Firewall e2e',
manifestPathCount: 'Manifests',
localRamBlockCount: 'RAM blocks',
hypercoreLengthHint: 'Core length',
queueDepthEstimate: 'Queue estimate',
snapshotWorkflowNote: 'Note',
activeSlot: 'Active slot',
pendingSlot: 'Pending',
previousSlot: 'Previous',
canarySlot: 'Canary',
drainDeadlineMs: 'Drain',
atMs: 'Updated'
}
if (known[key]) return known[key]
const s = String(key || '')
.replace(/[_-]+/g, ' ')
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
.replace(/\s+/g, ' ')
.trim()
if (!s) return String(key || '')
return s.charAt(0).toUpperCase() + s.slice(1)
} }
function discordCollectFields(obj, prefix, out, depth) { function discordCollectFields(obj, prefix, out, depth) {
if (!obj || typeof obj !== 'object' || Array.isArray(obj) || depth > 2) return if (!obj || typeof obj !== 'object' || Array.isArray(obj) || depth > 2) return
const keys = Object.keys(obj) const keys = Object.keys(obj)
for (let i = 0; i < keys.length && out.length < 25; i++) { for (let i = 0; i < keys.length && out.length < 18; i++) {
const k = keys[i] const k = keys[i]
if (discordSkipPrettyKey(k)) continue if (discordSkipPrettyKey(k)) continue
if (k === 'note' || k === 'schema') continue
const val = obj[k] const val = obj[k]
const label = prefix ? prefix + ' · ' + k : k if (discordValueEmpty(val)) continue
const label = prefix ? prefix + ' · ' + discordHumanLabel(k) : discordHumanLabel(k)
if (val && typeof val === 'object' && !Array.isArray(val) && depth < 2) { if (val && typeof val === 'object' && !Array.isArray(val) && depth < 2) {
const lines = []
const sub = Object.keys(val) const sub = Object.keys(val)
const flat = sub.every(function (sk) { for (let j = 0; j < sub.length && lines.length < 8; j++) {
const sv = val[sk]
return sv == null || typeof sv !== 'object'
})
if (flat && sub.length && sub.length <= 5) {
const parts = []
for (let j = 0; j < sub.length; j++) {
if (discordSkipPrettyKey(sub[j])) continue if (discordSkipPrettyKey(sub[j])) continue
parts.push(sub[j] + ': ' + discordPrettyValue(sub[j], val[sub[j]])) const sv = val[sub[j]]
if (discordValueEmpty(sv)) continue
if (sv && typeof sv === 'object') continue
const pretty = discordPrettyValue(sub[j], sv)
if (pretty === '—' || pretty === '(none)') continue
lines.push('**' + discordHumanLabel(sub[j]) + '** ' + pretty)
} }
if (parts.length) out.push(discordField(label, parts.join('\n'), true)) if (lines.length) out.push(discordField(discordHumanLabel(k), lines.join('\n'), false))
} else { } else {
discordCollectFields(val, label, out, depth + 1) const pretty = discordPrettyValue(k, val)
} if (pretty === '—' || pretty === '(none)') continue
} else { out.push(discordField(label, pretty, true))
out.push(discordField(label, discordPrettyValue(k, val), true))
} }
} }
} }
@@ -615,12 +665,12 @@ function discordPrettySnapshot(title, raw, extras) {
} }
const fields = [] const fields = []
discordCollectFields(parsed, '', fields, 0) discordCollectFields(parsed, '', fields, 0)
const note = typeof parsed.note === 'string' ? parsed.note.slice(0, 350) : '' const note = typeof parsed.note === 'string' ? parsed.note.slice(0, 280) : ''
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: title, title: title,
desc: note, desc: note,
fields: fields.slice(0, 25), fields: fields.slice(0, 18),
color: extras && extras.color color: extras && extras.color
}), }),
extras extras
@@ -750,7 +800,17 @@ function discordEmbed(opts) {
} }
if (o.title) e.title = String(o.title).slice(0, 256) if (o.title) e.title = String(o.title).slice(0, 256)
if (o.desc) e.description = discordCmdClip(discordCmdRedact(o.desc), 1800) if (o.desc) e.description = discordCmdClip(discordCmdRedact(o.desc), 1800)
if (o.fields && o.fields.length) e.fields = o.fields if (o.fields && o.fields.length) {
const fields = []
for (let i = 0; i < o.fields.length && fields.length < 25; i++) {
const f = o.fields[i]
if (!f) continue
const v = String(f.value == null ? '' : f.value).trim()
if (!v || v === '—') continue
fields.push(f)
}
if (fields.length) e.fields = fields
}
if (o.author) e.author = o.author if (o.author) e.author = o.author
return e return e
} }
@@ -1339,7 +1399,7 @@ async function discordFmView(ctx, interaction) {
if (listing.err) desc += '\n' + listing.err if (listing.err) desc += '\n' + listing.err
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Files · ' + discordSessionUser(ctx), title: 'Files',
desc: desc, desc: desc,
fields: fields.slice(0, 20), fields: fields.slice(0, 20),
color: rec.confirm ? BARE_OS_DISCORD_COLOR_ERR : BARE_OS_DISCORD_COLOR, color: rec.confirm ? BARE_OS_DISCORD_COLOR_ERR : BARE_OS_DISCORD_COLOR,
@@ -1435,17 +1495,17 @@ async function discordCmdHandleBare(ctx, sub) {
if (sub === 'help') { if (sub === 'help') {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Command map', title: 'Commands',
desc: 'Running as **' + user + '**. Use the buttons below, or slash commands.',
fields: [ fields: [
discordField('/bare', 'status · whoami · hostname · date · uptime · motd · uname · help'), discordField('/bare', 'Session — status, whoami, hostname, date, uptime, motd, uname'),
discordField('/sys', 'df · mem · ps · env · doctor · features · rlimits'), discordField('/sys', 'Host — disk, memory, processes, env, doctor, features, limits'),
discordField('/svc', 'list · status · start · stop · restart · logs *(unit autocomplete)*'), discordField('/svc', 'Services — list, start, stop, restart, logs'),
discordField('/fs', 'ls · cat · stat · head *(path autocomplete)*'), discordField('/fs', 'Read-only VFS — ls, cat, stat, head'),
discordField('/net', 'peers · swarm · summary'), discordField('/net', 'Swarm — peers, summary'),
discordField( discordField('/files /edit /create', 'Browse and edit files under `~/` and `/tmp`'),
'/files /edit /create /settings /man /run /journal /say /panel /ping', discordField('/settings', 'Live session knobs (theme, shell, Discord, agent, aliases)'),
'Files, settings editor, edit/create, lookups, run, logs' discordField('/run /journal /say /man', 'Allowlisted command, logs, speak, man pages')
)
] ]
}) })
) )
@@ -1455,12 +1515,12 @@ async function discordCmdHandleBare(ctx, sub) {
if (sub === 'whoami') { if (sub === 'whoami') {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'whoami', title: 'Whoami',
color: BARE_OS_DISCORD_COLOR_OK, color: BARE_OS_DISCORD_COLOR_OK,
fields: [ fields: [
discordField('User', user, true), discordField('User', user, true),
discordField('Home', e.HOME || '/home/' + user, true), discordField('Home', '`' + (e.HOME || '/home/' + user) + '`', true),
discordField('Identity', e.BARE_OS_IDENTITY || (ctx.identity && ctx.identity.state) || '', true) discordField('Identity', e.BARE_OS_IDENTITY || (ctx.identity && ctx.identity.state) || '', true)
] ]
}) })
) )
@@ -1468,7 +1528,7 @@ async function discordCmdHandleBare(ctx, sub) {
if (sub === 'hostname') { if (sub === 'hostname') {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'hostname', title: 'Hostname',
desc: '`' + String(e.HOSTNAME || e.NAME || 'bare-os') + '`' desc: '`' + String(e.HOSTNAME || e.NAME || 'bare-os') + '`'
}) })
) )
@@ -1476,8 +1536,8 @@ async function discordCmdHandleBare(ctx, sub) {
if (sub === 'date') { if (sub === 'date') {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'date', title: 'Date',
desc: new Date().toISOString() + '\n' + String(Date()) desc: '`' + new Date().toISOString() + '`'
}) })
) )
} }
@@ -1594,17 +1654,33 @@ function discordFormatRlimits(obj) {
const lim = obj && obj.rlimits && typeof obj.rlimits === 'object' ? obj.rlimits : obj const lim = obj && obj.rlimits && typeof obj.rlimits === 'object' ? obj.rlimits : obj
const fields = [] const fields = []
if (!lim || typeof lim !== 'object') return fields if (!lim || typeof lim !== 'object') return fields
const names = {
NOFILE: 'Open files',
NPROC: 'Processes',
AS: 'Address space',
DATA: 'Data',
STACK: 'Stack',
CORE: 'Core dump',
RSS: 'RSS',
CPU: 'CPU time',
FSIZE: 'File size',
NOVM: 'No VM',
MEMLOCK: 'Locked mem'
}
const keys = Object.keys(lim) const keys = Object.keys(lim)
for (let i = 0; i < keys.length && fields.length < 20; i++) { for (let i = 0; i < keys.length && fields.length < 18; i++) {
const v = lim[keys[i]] const raw = keys[i]
const v = lim[raw]
if (v && typeof v === 'object' && (v.cur != null || v.max != null)) { if (v && typeof v === 'object' && (v.cur != null || v.max != null)) {
const cur = discordIsByteishKey(keys[i]) ? discordPrettyBytes(v.cur) : String(v.cur) const short = raw.replace(/^RLIMIT_/, '')
const max = discordIsByteishKey(keys[i]) ? discordPrettyBytes(v.max) : String(v.max) const label = names[short] || discordHumanLabel(short)
fields.push(discordField(keys[i].replace(/^RLIMIT_/, ''), cur + ' / ' + max, true)) const cur = discordIsByteishKey(raw) ? discordPrettyBytes(v.cur) : String(v.cur)
const max = discordIsByteishKey(raw) ? discordPrettyBytes(v.max) : String(v.max)
fields.push(discordField(label, cur + ' / ' + max, true))
} }
} }
if (obj && obj.bareOsExecMaxDepth != null) { if (obj && obj.bareOsExecMaxDepth != null) {
fields.push(discordField('exec depth', String(obj.bareOsExecMaxDepth), true)) fields.push(discordField('Exec depth', String(obj.bareOsExecMaxDepth), true))
} }
return fields return fields
} }
@@ -1618,15 +1694,60 @@ function discordFormatFeatures(obj) {
const keys = Object.keys(feat).sort() const keys = Object.keys(feat).sort()
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
const v = feat[keys[i]] const v = feat[keys[i]]
if (v === true || v === 1 || v === '1') on.push(keys[i]) if (v === true || v === 1 || v === '1') on.push('`' + keys[i] + '`')
else if (v === false || v === 0 || v === '0') off.push(keys[i]) else if (v === false || v === 0 || v === '0') off.push('`' + keys[i] + '`')
} }
const fields = [] const fields = []
if (on.length) fields.push(discordField('Enabled', on.slice(0, 30).join(', '))) if (on.length) fields.push(discordField('On', on.slice(0, 24).join(' ')))
if (off.length) fields.push(discordField('Off', off.slice(0, 20).join(', '))) if (off.length) fields.push(discordField('Off', off.slice(0, 16).join(' ')))
return fields return fields
} }
function discordFormatDoctor(obj) {
if (!obj || typeof obj !== 'object') {
return { fields: [], desc: '', color: BARE_OS_DISCORD_COLOR_WARN }
}
const pa = obj.peerAdmission && typeof obj.peerAdmission === 'object' ? obj.peerAdmission : {}
const hn = obj.hostnameMutation && typeof obj.hostnameMutation === 'object' ? obj.hostnameMutation : {}
const kh = obj.keyHandlePolicy && typeof obj.keyHandlePolicy === 'object' ? obj.keyHandlePolicy : {}
const fields = []
if (pa.allowlistConfigured != null) {
fields.push(discordField('Peer allowlist', pa.allowlistConfigured ? 'configured' : 'open', true))
}
if (pa.denylistConfigured != null) {
fields.push(discordField('Peer denylist', pa.denylistConfigured ? 'configured' : 'none', true))
}
if (pa.requireCapsConfigured != null) {
const n = pa.requireCapsTokenCount
fields.push(
discordField(
'Require caps',
pa.requireCapsConfigured ? (n ? n + ' tokens' : 'yes') : 'no',
true
)
)
}
if (hn.enabled != null) {
fields.push(discordField('Hostname set', hn.enabled ? 'allowed' : 'locked', true))
}
if (kh.defaultTtlMs) {
fields.push(discordField('Key TTL', discordPrettyValue('defaultTtlMs', kh.defaultTtlMs), true))
}
if (Array.isArray(obj.mfaExtensionPoints) && obj.mfaExtensionPoints.length) {
fields.push(discordField('MFA hooks', obj.mfaExtensionPoints.join(' · '), false))
}
const bits = []
if (pa.allowlistConfigured) bits.push('peer allowlist on')
else if (pa.allowlistConfigured === false) bits.push('peer allowlist **open**')
if (hn.enabled === true) bits.push('hostname mutation on')
else if (hn.enabled === false) bits.push('hostname locked')
return {
fields: fields,
desc: bits.join(' · '),
color: pa.allowlistConfigured ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN
}
}
async function discordCmdHandleSys(ctx, sub) { async function discordCmdHandleSys(ctx, sub) {
if (sub === 'df') { if (sub === 'df') {
const t = const t =
@@ -1659,42 +1780,65 @@ async function discordCmdHandleSys(ctx, sub) {
const table = await discordCmdReadJson(ctx, '/proc/bare_os/process_table.json') const table = await discordCmdReadJson(ctx, '/proc/bare_os/process_table.json')
const rows = table && Array.isArray(table.processes) ? table.processes : [] const rows = table && Array.isArray(table.processes) ? table.processes : []
const fields = [] const fields = []
for (let i = 0; i < Math.min(rows.length, 20); i++) { for (let i = 0; i < Math.min(rows.length, 18); i++) {
const r = rows[i] || {} const r = rows[i] || {}
const name = String(r.name || r.comm || r.cmd || r.id || 'proc') const name = String(r.name || r.comm || r.cmd || r.id || 'proc')
const st = String(r.state || r.status || '') const st = String(r.state || r.status || '')
const pid = String(r.pid || r.id || i) const pid = String(r.pid || r.id || i)
fields.push(discordField('#' + pid + ' ' + name, st, true)) fields.push(discordField(name, 'pid ' + pid + (st ? ' · ' + st : ''), true))
} }
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Processes · ' + rows.length, title: 'Processes · ' + rows.length,
desc: rows.length ? '' : 'No logical processes in the session table.', desc: rows.length ? rows.length + ' logical processes in this session.' : 'No logical processes in the session table.',
fields: fields fields: fields
}) })
) )
} }
if (sub === 'env') { if (sub === 'env') {
const e = discordCmdEnv(ctx) const e = discordCmdEnv(ctx)
const ident = [ const fields = [
discordField('USER', e.USER, true), discordField('User', e.USER, true),
discordField('HOME', e.HOME, true), discordField('Home', e.HOME, true),
discordField('SHELL', e.SHELL, true),
discordField('PWD', e.PWD, true),
discordField('Identity', e.BARE_OS_IDENTITY, true), discordField('Identity', e.BARE_OS_IDENTITY, true),
discordField('UID/GID', String(e.UID || '—') + ' / ' + String(e.GID || '—'), true) discordField('Shell', e.SHELL, true),
discordField('Pwd', e.PWD, true),
discordField(
'UID / GID',
e.UID || e.GID ? String(e.UID || '—') + ' / ' + String(e.GID || '—') : '',
true
)
]
const prefer = [
'HOSTNAME',
'PATH',
'TERM',
'TZ',
'LANG',
'EDITOR',
'PAGER',
'BARE_OS_THEME',
'BARE_OS_COLOR_DEPTH'
] ]
const skip = /TOKEN|SECRET|PASSWORD|PASSWD|KEY|PRIVATE|CREDENTIAL|^USER$|^HOME$|^SHELL$|^PWD$|^LOGNAME$|^UID$|^GID$|^GROUP$|^BARE_OS_IDENTITY$/i const skip = /TOKEN|SECRET|PASSWORD|PASSWD|KEY|PRIVATE|CREDENTIAL|^USER$|^HOME$|^SHELL$|^PWD$|^LOGNAME$|^UID$|^GID$|^GROUP$|^BARE_OS_IDENTITY$/i
const rest = [] const seen = Object.create(null)
for (let i = 0; i < prefer.length; i++) {
const k = prefer[i]
seen[k] = 1
if (e[k] == null || e[k] === '') continue
fields.push(discordField(discordHumanLabel(k.replace(/^BARE_OS_/, '')), String(e[k]).slice(0, 80), true))
}
const keys = Object.keys(e).sort() const keys = Object.keys(e).sort()
for (let i = 0; i < keys.length && rest.length < 16; i++) { for (let i = 0; i < keys.length && fields.length < 15; i++) {
if (skip.test(keys[i])) continue if (seen[keys[i]] || skip.test(keys[i])) continue
rest.push(discordField(keys[i], String(e[keys[i]]).slice(0, 80), true)) if (e[keys[i]] == null || e[keys[i]] === '') continue
fields.push(discordField(keys[i], String(e[keys[i]]).slice(0, 72), true))
} }
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Environment · ' + discordSessionUser(ctx), title: 'Environment',
fields: ident.concat(rest) desc: 'Session env for **' + discordSessionUser(ctx) + '** (secrets omitted).',
fields: fields
}), }),
{ ephemeral: true } { ephemeral: true }
) )
@@ -1704,10 +1848,18 @@ async function discordCmdHandleSys(ctx, sub) {
(await discordCmdReadText(ctx, '/proc/bare_os/security_posture.json')) || (await discordCmdReadText(ctx, '/proc/bare_os/security_posture.json')) ||
(await discordCmdReadText(ctx, '/proc/bare_os/debug.json')) (await discordCmdReadText(ctx, '/proc/bare_os/debug.json'))
const obj = discordTryJson(t) const obj = discordTryJson(t)
const pa = obj && obj.peerAdmission const fmt = obj ? discordFormatDoctor(obj) : null
const color = if (fmt && fmt.fields.length) {
pa && pa.allowlistConfigured ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN return discordResult(
return discordPrettySnapshot('Doctor', t, { color: color }) discordEmbed({
title: 'Doctor',
desc: fmt.desc,
fields: fmt.fields,
color: fmt.color
})
)
}
return discordPrettySnapshot('Doctor', t, { color: fmt && fmt.color })
} }
if (sub === 'features') { if (sub === 'features') {
const t = const t =
@@ -1717,7 +1869,13 @@ async function discordCmdHandleSys(ctx, sub) {
const obj = discordTryJson(t) const obj = discordTryJson(t)
const fields = obj ? discordFormatFeatures(obj) : [] const fields = obj ? discordFormatFeatures(obj) : []
if (fields.length) { if (fields.length) {
return discordResult(discordEmbed({ title: 'Features', fields: fields })) return discordResult(
discordEmbed({
title: 'Features',
desc: 'Guest capability flags on this booter.',
fields: fields
})
)
} }
return discordPrettySnapshot('Features', t) return discordPrettySnapshot('Features', t)
} }
@@ -1729,7 +1887,7 @@ async function discordCmdHandleSys(ctx, sub) {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Resource limits', title: 'Resource limits',
desc: 'soft / hard · Bare OS runtime caps (not Linux rlimits)', desc: 'Soft / hard · Bare OS runtime caps (not Linux rlimits).',
fields: fields fields: fields
}) })
) )
@@ -1752,14 +1910,11 @@ async function discordCmdHandleSvc(ctx, sub, unit) {
const fields = [] const fields = []
for (let i = 0; i < parsed.length && fields.length < 20; i++) { for (let i = 0; i < parsed.length && fields.length < 20; i++) {
const r = parsed[i] const r = parsed[i]
const st = (r.active || '—') + (r.sub ? ' / ' + r.sub : '') const bits = []
fields.push( if (r.active) bits.push('**' + r.active + '**')
discordField( if (r.sub && r.sub !== r.active) bits.push(r.sub)
r.unit, if (r.preset && r.preset !== 'enabled') bits.push(r.preset)
st + (r.preset && r.preset !== 'enabled' ? ' · ' + r.preset : ''), fields.push(discordField(r.unit, bits.join(' · ') || 'unknown', true))
true
)
)
} }
const units = await discordSuggestUnits(ctx, '') const units = await discordSuggestUnits(ctx, '')
const sel = discordSelect( const sel = discordSelect(
@@ -1772,7 +1927,11 @@ async function discordCmdHandleSvc(ctx, sub, unit) {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Services · ' + (parsed.length || 0), title: 'Services · ' + (parsed.length || 0),
desc: parsed.length ? '' : out ? discordCmdClip(out, 800) : '(no units)', desc: parsed.length
? 'Pick a unit to inspect, start, or stop.'
: out
? discordCmdClip(out, 800)
: 'No units registered in this session.',
fields: fields, fields: fields,
color: BARE_OS_DISCORD_COLOR color: BARE_OS_DISCORD_COLOR
}), }),
@@ -1804,8 +1963,11 @@ async function discordCmdHandleSvc(ctx, sub, unit) {
discordEmbed({ discordEmbed({
title: name, title: name,
desc: out desc: out
? '**systemctl ' + sub + '**\n' + discordCmdClip(discordCmdRedact(out), 1200) ? '`' +
: '(no output)', sub +
'`\n' +
discordCmdFence(discordCmdClip(discordCmdRedact(out), 1100))
: 'No output from `systemctl ' + sub + '`.',
color: color color: color
}), }),
{ components: act ? [act] : [] } { components: act ? [act] : [] }
@@ -1835,11 +1997,18 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
: '(empty)' : '(empty)'
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'ls ' + p, title: 'Listing',
desc: desc:
'`' +
p +
'` · ' +
list.length +
' ' +
(list.length === 1 ? 'entry' : 'entries') +
'\n' +
desc + desc +
(list.length > shown.length ? '\n+' + (list.length - shown.length) + ' more' : ''), (list.length > shown.length ? '\n+' + (list.length - shown.length) + ' more' : ''),
footer: list.length + ' entries · ' + discordSessionUser(ctx) footer: discordSessionUser(ctx)
}) })
) )
} catch (err) { } catch (err) {
@@ -1868,14 +2037,12 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
discordField('Modified', Number.isFinite(ms) ? new Date(ms).toISOString() : String(st.mtime), true) discordField('Modified', Number.isFinite(ms) ? new Date(ms).toISOString() : String(st.mtime), true)
) )
} }
if (st.path) fields.push(discordField('Path', String(st.path), false)) if (st.path && st.path !== p) fields.push(discordField('Resolved', String(st.path), false))
if (fields.length < 4) {
discordCollectFields(st, '', fields, 0)
}
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'stat ' + p, title: 'Stat',
fields: fields.slice(0, 20) desc: '`' + p + '`',
fields: fields.slice(0, 12)
}) })
) )
} catch (err) { } catch (err) {
@@ -1884,7 +2051,7 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
} }
const text = await discordCmdReadText(ctx, p) const text = await discordCmdReadText(ctx, p)
if (!text) { if (!text) {
return discordResult(discordEmbed({ title: p, desc: '(empty or unreadable)' })) return discordResult(discordEmbed({ title: 'File', desc: '`' + p + '` is empty or unreadable.' }))
} }
const writable = Boolean(discordCmdPathWriteOk(ctx, p)) const writable = Boolean(discordCmdPathWriteOk(ctx, p))
const editRow = writable const editRow = writable
@@ -1896,63 +2063,148 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
} }
const asJson = discordTryJson(text) const asJson = discordTryJson(text)
if (asJson && typeof asJson === 'object' && !Array.isArray(asJson)) { if (asJson && typeof asJson === 'object' && !Array.isArray(asJson)) {
return discordPrettySnapshot((sub === 'head' ? 'head ' : '') + p, asJson, extra) return discordPrettySnapshot(p, asJson, extra)
} }
if (sub === 'head') { if (sub === 'head') {
const n = Math.max(1, Math.min(40, Number(nlines) || 12)) const n = Math.max(1, Math.min(40, Number(nlines) || 12))
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'head ' + p, title: 'Head',
desc: discordCmdFence(text.split(/\r?\n/).slice(0, n).join('\n')) desc: '`' + p + '` · first ' + n + ' lines\n' + discordCmdFence(text.split(/\r?\n/).slice(0, n).join('\n'))
}), }),
extra extra
) )
} }
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: p, title: 'File',
desc: discordCmdFence(text.slice(0, BARE_OS_DISCORD_FS_MAX)), desc: '`' + p + '`\n' + discordCmdFence(text.slice(0, BARE_OS_DISCORD_FS_MAX)),
footer: text.length + ' bytes · ' + discordSessionUser(ctx) footer: text.length + ' bytes · ' + discordSessionUser(ctx)
}), }),
extra extra
) )
} }
function discordFormatNetSummary(obj) {
if (!obj || typeof obj !== 'object') {
return { fields: [], desc: '', color: BARE_OS_DISCORD_COLOR }
}
const rq =
obj.replicationQueue && typeof obj.replicationQueue === 'object' ? obj.replicationQueue : {}
const st = obj.stagingSlot && typeof obj.stagingSlot === 'object' ? obj.stagingSlot : {}
const fields = []
const peers = obj.peerCount
const role = obj.seedRole || rq.role || st.role
const proto = rq.protocol || st.protocol || obj.protocol
if (peers != null) fields.push(discordField('Peers', String(peers), true))
if (role) fields.push(discordField('Role', String(role), true))
if (proto) fields.push(discordField('Protocol', '`' + String(proto) + '`', true))
if (obj.topicHex) {
const hex = String(obj.topicHex)
fields.push(
discordField('Topic', '`' + hex.slice(0, 16) + (hex.length > 16 ? '…' : '') + '`', true)
)
}
if (obj.replicationQueueDepth != null) {
fields.push(discordField('Queue depth', String(obj.replicationQueueDepth), true))
}
if (rq.queueDepthEstimate != null) {
fields.push(discordField('Queue estimate', String(rq.queueDepthEstimate), true))
}
if (rq.hypercoreLengthHint != null) {
fields.push(discordField('Core length', String(rq.hypercoreLengthHint), true))
}
if (rq.manifestPathCount != null) {
fields.push(discordField('Manifests', String(rq.manifestPathCount), true))
}
if (rq.localRamBlockCount != null) {
fields.push(discordField('RAM blocks', String(rq.localRamBlockCount), true))
}
if (st.activeSlot) fields.push(discordField('Active slot', String(st.activeSlot), true))
const fwA = obj.peerFirewallAcceptedTotal
const fwR = obj.peerFirewallRejectedTotal
const fwI = obj.peerFirewallInboundTotal
const fwO = obj.peerFirewallOutboundTotal
if (fwA != null || fwR != null || fwI != null || fwO != null) {
fields.push(
discordField(
'Firewall',
'accept ' +
(fwA == null ? '0' : fwA) +
' · reject ' +
(fwR == null ? '0' : fwR) +
'\nin ' +
(fwI == null ? '0' : fwI) +
' · out ' +
(fwO == null ? '0' : fwO),
true
)
)
}
if (obj.seedHandshakeError) {
fields.push(discordField('Handshake', String(obj.seedHandshakeError), false))
}
const peerN = Number(peers)
const head = []
if (Number.isFinite(peerN)) head.push('**' + peerN + '** peer' + (peerN === 1 ? '' : 's'))
if (role) head.push(String(role))
if (proto) head.push('`' + proto + '`')
let desc = head.join(' · ')
const note = rq.snapshotWorkflowNote || obj.note
if (note) desc += (desc ? '\n' : '') + '*' + String(note).slice(0, 220) + '*'
const at = rq.atMs || obj.atMs
return {
fields: fields,
desc: desc,
color: Number.isFinite(peerN) && peerN > 0 ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN,
footer: at ? 'Updated ' + new Date(Number(at)).toISOString() + ' · expires after 2m idle' : ''
}
}
function discordFormatSwarm(obj) { function discordFormatSwarm(obj) {
if (!obj || typeof obj !== 'object') return [] if (!obj || typeof obj !== 'object') return []
const fields = [] const fields = []
if (obj.peerCount != null) fields.push(discordField('Peers', String(obj.peerCount), true)) if (obj.peerCount != null) fields.push(discordField('Peers', String(obj.peerCount), true))
if (obj.protocol) fields.push(discordField('Protocol', String(obj.protocol), true)) if (obj.protocol) fields.push(discordField('Protocol', '`' + String(obj.protocol) + '`', true))
if (obj.topicCount != null) fields.push(discordField('Topics', String(obj.topicCount), true)) if (obj.topicCount != null) fields.push(discordField('Topics', String(obj.topicCount), true))
if (obj.topicHex) { if (obj.topicHex) {
fields.push(discordField('Topic', String(obj.topicHex).slice(0, 16) + '…', true)) const hex = String(obj.topicHex)
fields.push(
discordField('Topic', '`' + hex.slice(0, 16) + (hex.length > 16 ? '…' : '') + '`', true)
)
} }
const lc = obj.lifecycle const lc = obj.lifecycle
if (lc && typeof lc === 'object') { if (lc && typeof lc === 'object') {
const bits = [] const bits = []
const lk = Object.keys(lc) const lk = Object.keys(lc)
for (let i = 0; i < lk.length && bits.length < 6; i++) { for (let i = 0; i < lk.length && bits.length < 6; i++) {
if (typeof lc[lk[i]] !== 'object') bits.push(lk[i] + ': ' + discordPrettyValue(lk[i], lc[lk[i]])) if (typeof lc[lk[i]] === 'object' || discordValueEmpty(lc[lk[i]])) continue
bits.push('**' + discordHumanLabel(lk[i]) + '** ' + discordPrettyValue(lk[i], lc[lk[i]]))
} }
if (bits.length) fields.push(discordField('Lifecycle', bits.join('\n'), true)) if (bits.length) fields.push(discordField('Lifecycle', bits.join('\n'), false))
} }
const sc = obj.peerScoringAggregates const sc = obj.peerScoringAggregates
if (sc && typeof sc === 'object') { if (sc && typeof sc === 'object') {
const banned = sc.bannedActiveCount
const hi = sc.highLatencyEwmaCount
const low = sc.lowSuccessRateBucketCount
if (banned != null || hi != null || low != null) {
fields.push( fields.push(
discordField( discordField(
'Scoring', 'Scoring',
'banned ' + 'banned ' +
String(sc.bannedActiveCount || 0) + String(banned || 0) +
' · high-lat ' + ' · high-lat ' +
String(sc.highLatencyEwmaCount || 0) + String(hi || 0) +
' · low-ok ' + ' · low-ok ' +
String(sc.lowSuccessRateBucketCount || 0), String(low || 0),
true true
) )
) )
} }
}
if (Array.isArray(obj.peers) && obj.peers.length) { if (Array.isArray(obj.peers) && obj.peers.length) {
fields.push(discordField('Peer rows', String(obj.peers.length), true)) fields.push(discordField('Peer list', String(obj.peers.length), true))
} }
return fields return fields
} }
@@ -1966,9 +2218,14 @@ async function discordCmdHandleNet(ctx, sub) {
const obj = discordTryJson(t) const obj = discordTryJson(t)
const fields = obj ? discordFormatSwarm(obj) : [] const fields = obj ? discordFormatSwarm(obj) : []
if (fields.length) { if (fields.length) {
const n = obj && obj.peerCount
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Swarm', title: 'Swarm',
desc:
n != null
? '**' + n + '** peer' + (Number(n) === 1 ? '' : 's') + (obj.protocol ? ' · `' + obj.protocol + '`' : '')
: '',
fields: fields, fields: fields,
color: obj && obj.peerCount > 0 ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN color: obj && obj.peerCount > 0 ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN
}) })
@@ -1980,7 +2237,21 @@ async function discordCmdHandleNet(ctx, sub) {
(await discordCmdReadText(ctx, '/proc/bare_os/net_summary.json')) || (await discordCmdReadText(ctx, '/proc/bare_os/net_summary.json')) ||
(await discordCmdReadText(ctx, '/proc/net/dev')) (await discordCmdReadText(ctx, '/proc/net/dev'))
const obj = discordTryJson(t) const obj = discordTryJson(t)
if (obj) return discordPrettySnapshot('Network', obj) if (obj) {
const fmt = discordFormatNetSummary(obj)
if (fmt.fields.length) {
return discordResult(
discordEmbed({
title: 'Network',
desc: fmt.desc,
fields: fmt.fields,
color: fmt.color,
footer: fmt.footer || undefined
})
)
}
return discordPrettySnapshot('Network', obj)
}
if (t && t.indexOf('Inter-|') >= 0) { if (t && t.indexOf('Inter-|') >= 0) {
const lines = t.split(/\r?\n/).filter(Boolean) const lines = t.split(/\r?\n/).filter(Boolean)
return discordResult( return discordResult(
@@ -2083,7 +2354,7 @@ async function discordCmdHandleRun(ctx, raw) {
title: '$ ' + key, title: '$ ' + key,
footer: 'ran as ' + discordSessionUser(ctx), footer: 'ran as ' + discordSessionUser(ctx),
desc: out desc: out
? discordCmdClip(discordCmdRedact(out), 1500) ? discordCmdFence(discordCmdClip(discordCmdRedact(out), 1400))
: '(no output, exit ' + String(ctx.exitCode || 0) + ')' : '(no output, exit ' + String(ctx.exitCode || 0) + ')'
}) })
) )
@@ -2106,14 +2377,16 @@ async function discordCmdHandleJournal(ctx, unit) {
.slice(-20) .slice(-20)
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'journal · ' + unit, title: 'Journal · ' + unit,
desc: lines.length desc: lines.length
? lines ? discordCmdFence(
lines
.map(function (ln) { .map(function (ln) {
return discordCmdRedact(ln).slice(0, 180) return discordCmdRedact(ln).slice(0, 180)
}) })
.join('\n') .join('\n')
: '(empty journal)' )
: 'Empty journal for `' + unit + '`.'
}) })
) )
} }
@@ -2127,14 +2400,16 @@ async function discordCmdHandleJournal(ctx, unit) {
.slice(-18) .slice(-18)
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'journal', title: 'Journal',
desc: lines.length desc: lines.length
? lines ? discordCmdFence(
lines
.map(function (ln) { .map(function (ln) {
return discordCmdRedact(ln).slice(0, 180) return discordCmdRedact(ln).slice(0, 180)
}) })
.join('\n') .join('\n')
: '(no journal)' )
: 'No journal in `/var/log/bare-os`.'
}) })
) )
} }
@@ -2149,11 +2424,12 @@ function discordPanel(ctx) {
desc: desc:
'Signed in as **' + 'Signed in as **' +
user + user +
'** · home `' + '** · `' +
(e.HOME || '/home/' + user) + (e.HOME || '/home/' + user) +
'`\nUse the buttons, or slash commands with autocomplete.', '`\nPick a button, or use a slash command.',
fields: [ fields: [
discordField('Identity', e.BARE_OS_IDENTITY || (ctx.identity && ctx.identity.state) || '—', true), discordField('User', user, true),
discordField('Identity', e.BARE_OS_IDENTITY || (ctx.identity && ctx.identity.state) || '', true),
discordField('Host', e.HOSTNAME || 'bare-os', true) discordField('Host', e.HOSTNAME || 'bare-os', true)
] ]
}) })
@@ -3394,10 +3670,10 @@ async function discordSettingsView(ctx, interaction) {
rec.page = pg.page rec.page = pg.page
pages = pg.pages pages = pg.pages
page = pg.page page = pg.page
if (!entries.length) fields.push(discordField('aliases', '(none)')) if (!entries.length) fields.push(discordField('Aliases', 'None defined. Add one from the menu.'))
for (let i = 0; i < pg.slice.length; i++) { for (let i = 0; i < pg.slice.length; i++) {
const e = pg.slice[i] const e = pg.slice[i]
fields.push(discordField((rec.sel === e.name ? '▸ ' : '') + e.name, e.value || '(empty)')) fields.push(discordField((rec.sel === e.name ? '▸ ' : '') + e.name, '`' + (e.value || '') + '`'))
} }
itemOpts = [{ label: 'Add alias', value: 'alias_add', description: 'name=command' }].concat( itemOpts = [{ label: 'Add alias', value: 'alias_add', description: 'name=command' }].concat(
pg.slice.map(function (e) { pg.slice.map(function (e) {
@@ -3416,7 +3692,7 @@ async function discordSettingsView(ctx, interaction) {
fields.push( fields.push(
discordField( discordField(
(rec.sel === spec.id ? '▸ ' : '') + spec.label, (rec.sel === spec.id ? '▸ ' : '') + spec.label,
discordSettingsDisplay(spec, cur) + ' · ' + spec.live '**' + discordSettingsDisplay(spec, cur) + '**\n' + spec.live
) )
) )
} }
@@ -3448,12 +3724,9 @@ async function discordSettingsView(ctx, interaction) {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Settings · ' + meta.label + (pages > 1 ? ' · ' + (page + 1) + '/' + pages : ''), title: 'Settings · ' + meta.label + (pages > 1 ? ' · ' + (page + 1) + '/' + pages : ''),
desc: desc: meta.description + '. Secrets are never shown. Pick a row, then **Edit** or **Toggle**.',
'Live-safe session knobs only. Tokens, API keys, and passwords are never shown or written.\n' +
meta.description +
' — persist to `~/.barerc`, `~/.discord/.env` (non-secret keys), or app JSON.',
fields: fields.slice(0, 20), fields: fields.slice(0, 20),
footer: discordSessionUser(ctx) + ' · pick a setting, then Edit / Toggle' footer: discordSessionUser(ctx) + ' · expires after 2m idle'
}), }),
{ components: [gsel, isel, acts, pageRow].filter(Boolean), nav: false } { components: [gsel, isel, acts, pageRow].filter(Boolean), nav: false }
) )
@@ -4619,7 +4892,9 @@ var bareOsDiscordCommands = {
parseSystemctlList: discordParseSystemctlList, parseSystemctlList: discordParseSystemctlList,
formatRlimits: discordFormatRlimits, formatRlimits: discordFormatRlimits,
formatFeatures: discordFormatFeatures, formatFeatures: discordFormatFeatures,
formatDoctor: discordFormatDoctor,
formatSwarm: discordFormatSwarm, formatSwarm: discordFormatSwarm,
formatNetSummary: discordFormatNetSummary,
formatHostDf: discordFormatHostDf, formatHostDf: discordFormatHostDf,
pathWriteOk: discordCmdPathWriteOk, pathWriteOk: discordCmdPathWriteOk,
editChunks: discordEditChunks, editChunks: discordEditChunks,
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"schema": 2, "schema": 2,
"profileId": "bare-os-posix-like", "profileId": "bare-os-posix-like",
"generatedAt": "2026-08-13T18:01:27.382Z", "generatedAt": "2026-08-13T18:10:42.974Z",
"note": "Sparse POSIX Issue 7 coverage hints; commandIndex is generated each coreutils build.", "note": "Sparse POSIX Issue 7 coverage hints; commandIndex is generated each coreutils build.",
"commandIndex": [ "commandIndex": [
{ {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"schema": 1, "schema": 1,
"atMs": 1786644087376, "atMs": 1786644642972,
"commands": [ "commands": [
"agent", "agent",
"appctl", "appctl",
File diff suppressed because one or more lines are too long
@@ -189,7 +189,7 @@ function discordPrettyValue(key, val) {
} }
if (typeof val === 'string') { if (typeof val === 'string') {
const t = discordCmdRedact(val) const t = discordCmdRedact(val)
if (/^[0-9a-f]{24,}$/i.test(t)) return t.slice(0, 12) + '…' if (/^[0-9a-f]{24,}$/i.test(t)) return '`' + t.slice(0, 16) + (t.length > 16 ? '…' : '') + '`'
return t.length > 180 ? t.slice(0, 177) + '…' : t return t.length > 180 ? t.slice(0, 177) + '…' : t
} }
if (Array.isArray(val)) { if (Array.isArray(val)) {
@@ -207,36 +207,86 @@ function discordPrettyValue(key, val) {
} }
function discordSkipPrettyKey(k) { function discordSkipPrettyKey(k) {
return /TOKEN|SECRET|PASSWORD|PASSWD|PRIVATE|CREDENTIAL|API_KEY/i.test(k) return /TOKEN|SECRET|PASSWORD|PASSWD|PRIVATE|CREDENTIAL|API_KEY/i.test(k) ||
k === 'note' ||
k === 'schema' ||
k === 'schemaVersion'
}
function discordValueEmpty(val) {
if (val == null) return true
if (val === '') return true
if (val === '—') return true
if (Array.isArray(val) && !val.length) return true
if (typeof val === 'object' && !Array.isArray(val) && !Object.keys(val).length) return true
return false
}
function discordHumanLabel(key) {
const known = {
schemaVersion: 'Schema',
topicHex: 'Topic',
peerCount: 'Peers',
seedHandshakeError: 'Handshake',
seedRole: 'Role',
replicationQueueDepth: 'Queue depth',
replicationQueue: 'Replication',
stagingSlot: 'Staging',
snapshotHints: 'Snapshot',
peerFirewallStats: 'Firewall',
peerFirewallAcceptedTotal: 'Accepted',
peerFirewallRejectedTotal: 'Rejected',
peerFirewallInboundTotal: 'Inbound',
peerFirewallOutboundTotal: 'Outbound',
peerFirewallE2e: 'Firewall e2e',
manifestPathCount: 'Manifests',
localRamBlockCount: 'RAM blocks',
hypercoreLengthHint: 'Core length',
queueDepthEstimate: 'Queue estimate',
snapshotWorkflowNote: 'Note',
activeSlot: 'Active slot',
pendingSlot: 'Pending',
previousSlot: 'Previous',
canarySlot: 'Canary',
drainDeadlineMs: 'Drain',
atMs: 'Updated'
}
if (known[key]) return known[key]
const s = String(key || '')
.replace(/[_-]+/g, ' ')
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
.replace(/\s+/g, ' ')
.trim()
if (!s) return String(key || '')
return s.charAt(0).toUpperCase() + s.slice(1)
} }
function discordCollectFields(obj, prefix, out, depth) { function discordCollectFields(obj, prefix, out, depth) {
if (!obj || typeof obj !== 'object' || Array.isArray(obj) || depth > 2) return if (!obj || typeof obj !== 'object' || Array.isArray(obj) || depth > 2) return
const keys = Object.keys(obj) const keys = Object.keys(obj)
for (let i = 0; i < keys.length && out.length < 25; i++) { for (let i = 0; i < keys.length && out.length < 18; i++) {
const k = keys[i] const k = keys[i]
if (discordSkipPrettyKey(k)) continue if (discordSkipPrettyKey(k)) continue
if (k === 'note' || k === 'schema') continue
const val = obj[k] const val = obj[k]
const label = prefix ? prefix + ' · ' + k : k if (discordValueEmpty(val)) continue
const label = prefix ? prefix + ' · ' + discordHumanLabel(k) : discordHumanLabel(k)
if (val && typeof val === 'object' && !Array.isArray(val) && depth < 2) { if (val && typeof val === 'object' && !Array.isArray(val) && depth < 2) {
const lines = []
const sub = Object.keys(val) const sub = Object.keys(val)
const flat = sub.every(function (sk) { for (let j = 0; j < sub.length && lines.length < 8; j++) {
const sv = val[sk]
return sv == null || typeof sv !== 'object'
})
if (flat && sub.length && sub.length <= 5) {
const parts = []
for (let j = 0; j < sub.length; j++) {
if (discordSkipPrettyKey(sub[j])) continue if (discordSkipPrettyKey(sub[j])) continue
parts.push(sub[j] + ': ' + discordPrettyValue(sub[j], val[sub[j]])) const sv = val[sub[j]]
if (discordValueEmpty(sv)) continue
if (sv && typeof sv === 'object') continue
const pretty = discordPrettyValue(sub[j], sv)
if (pretty === '—' || pretty === '(none)') continue
lines.push('**' + discordHumanLabel(sub[j]) + '** ' + pretty)
} }
if (parts.length) out.push(discordField(label, parts.join('\n'), true)) if (lines.length) out.push(discordField(discordHumanLabel(k), lines.join('\n'), false))
} else { } else {
discordCollectFields(val, label, out, depth + 1) const pretty = discordPrettyValue(k, val)
} if (pretty === '—' || pretty === '(none)') continue
} else { out.push(discordField(label, pretty, true))
out.push(discordField(label, discordPrettyValue(k, val), true))
} }
} }
} }
@@ -302,12 +352,12 @@ function discordPrettySnapshot(title, raw, extras) {
} }
const fields = [] const fields = []
discordCollectFields(parsed, '', fields, 0) discordCollectFields(parsed, '', fields, 0)
const note = typeof parsed.note === 'string' ? parsed.note.slice(0, 350) : '' const note = typeof parsed.note === 'string' ? parsed.note.slice(0, 280) : ''
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: title, title: title,
desc: note, desc: note,
fields: fields.slice(0, 25), fields: fields.slice(0, 18),
color: extras && extras.color color: extras && extras.color
}), }),
extras extras
@@ -437,7 +487,17 @@ function discordEmbed(opts) {
} }
if (o.title) e.title = String(o.title).slice(0, 256) if (o.title) e.title = String(o.title).slice(0, 256)
if (o.desc) e.description = discordCmdClip(discordCmdRedact(o.desc), 1800) if (o.desc) e.description = discordCmdClip(discordCmdRedact(o.desc), 1800)
if (o.fields && o.fields.length) e.fields = o.fields if (o.fields && o.fields.length) {
const fields = []
for (let i = 0; i < o.fields.length && fields.length < 25; i++) {
const f = o.fields[i]
if (!f) continue
const v = String(f.value == null ? '' : f.value).trim()
if (!v || v === '—') continue
fields.push(f)
}
if (fields.length) e.fields = fields
}
if (o.author) e.author = o.author if (o.author) e.author = o.author
return e return e
} }
@@ -1026,7 +1086,7 @@ async function discordFmView(ctx, interaction) {
if (listing.err) desc += '\n' + listing.err if (listing.err) desc += '\n' + listing.err
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Files · ' + discordSessionUser(ctx), title: 'Files',
desc: desc, desc: desc,
fields: fields.slice(0, 20), fields: fields.slice(0, 20),
color: rec.confirm ? BARE_OS_DISCORD_COLOR_ERR : BARE_OS_DISCORD_COLOR, color: rec.confirm ? BARE_OS_DISCORD_COLOR_ERR : BARE_OS_DISCORD_COLOR,
@@ -1122,17 +1182,17 @@ async function discordCmdHandleBare(ctx, sub) {
if (sub === 'help') { if (sub === 'help') {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Command map', title: 'Commands',
desc: 'Running as **' + user + '**. Use the buttons below, or slash commands.',
fields: [ fields: [
discordField('/bare', 'status · whoami · hostname · date · uptime · motd · uname · help'), discordField('/bare', 'Session — status, whoami, hostname, date, uptime, motd, uname'),
discordField('/sys', 'df · mem · ps · env · doctor · features · rlimits'), discordField('/sys', 'Host — disk, memory, processes, env, doctor, features, limits'),
discordField('/svc', 'list · status · start · stop · restart · logs *(unit autocomplete)*'), discordField('/svc', 'Services — list, start, stop, restart, logs'),
discordField('/fs', 'ls · cat · stat · head *(path autocomplete)*'), discordField('/fs', 'Read-only VFS — ls, cat, stat, head'),
discordField('/net', 'peers · swarm · summary'), discordField('/net', 'Swarm — peers, summary'),
discordField( discordField('/files /edit /create', 'Browse and edit files under `~/` and `/tmp`'),
'/files /edit /create /settings /man /run /journal /say /panel /ping', discordField('/settings', 'Live session knobs (theme, shell, Discord, agent, aliases)'),
'Files, settings editor, edit/create, lookups, run, logs' discordField('/run /journal /say /man', 'Allowlisted command, logs, speak, man pages')
)
] ]
}) })
) )
@@ -1142,12 +1202,12 @@ async function discordCmdHandleBare(ctx, sub) {
if (sub === 'whoami') { if (sub === 'whoami') {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'whoami', title: 'Whoami',
color: BARE_OS_DISCORD_COLOR_OK, color: BARE_OS_DISCORD_COLOR_OK,
fields: [ fields: [
discordField('User', user, true), discordField('User', user, true),
discordField('Home', e.HOME || '/home/' + user, true), discordField('Home', '`' + (e.HOME || '/home/' + user) + '`', true),
discordField('Identity', e.BARE_OS_IDENTITY || (ctx.identity && ctx.identity.state) || '', true) discordField('Identity', e.BARE_OS_IDENTITY || (ctx.identity && ctx.identity.state) || '', true)
] ]
}) })
) )
@@ -1155,7 +1215,7 @@ async function discordCmdHandleBare(ctx, sub) {
if (sub === 'hostname') { if (sub === 'hostname') {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'hostname', title: 'Hostname',
desc: '`' + String(e.HOSTNAME || e.NAME || 'bare-os') + '`' desc: '`' + String(e.HOSTNAME || e.NAME || 'bare-os') + '`'
}) })
) )
@@ -1163,8 +1223,8 @@ async function discordCmdHandleBare(ctx, sub) {
if (sub === 'date') { if (sub === 'date') {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'date', title: 'Date',
desc: new Date().toISOString() + '\n' + String(Date()) desc: '`' + new Date().toISOString() + '`'
}) })
) )
} }
@@ -1281,17 +1341,33 @@ function discordFormatRlimits(obj) {
const lim = obj && obj.rlimits && typeof obj.rlimits === 'object' ? obj.rlimits : obj const lim = obj && obj.rlimits && typeof obj.rlimits === 'object' ? obj.rlimits : obj
const fields = [] const fields = []
if (!lim || typeof lim !== 'object') return fields if (!lim || typeof lim !== 'object') return fields
const names = {
NOFILE: 'Open files',
NPROC: 'Processes',
AS: 'Address space',
DATA: 'Data',
STACK: 'Stack',
CORE: 'Core dump',
RSS: 'RSS',
CPU: 'CPU time',
FSIZE: 'File size',
NOVM: 'No VM',
MEMLOCK: 'Locked mem'
}
const keys = Object.keys(lim) const keys = Object.keys(lim)
for (let i = 0; i < keys.length && fields.length < 20; i++) { for (let i = 0; i < keys.length && fields.length < 18; i++) {
const v = lim[keys[i]] const raw = keys[i]
const v = lim[raw]
if (v && typeof v === 'object' && (v.cur != null || v.max != null)) { if (v && typeof v === 'object' && (v.cur != null || v.max != null)) {
const cur = discordIsByteishKey(keys[i]) ? discordPrettyBytes(v.cur) : String(v.cur) const short = raw.replace(/^RLIMIT_/, '')
const max = discordIsByteishKey(keys[i]) ? discordPrettyBytes(v.max) : String(v.max) const label = names[short] || discordHumanLabel(short)
fields.push(discordField(keys[i].replace(/^RLIMIT_/, ''), cur + ' / ' + max, true)) const cur = discordIsByteishKey(raw) ? discordPrettyBytes(v.cur) : String(v.cur)
const max = discordIsByteishKey(raw) ? discordPrettyBytes(v.max) : String(v.max)
fields.push(discordField(label, cur + ' / ' + max, true))
} }
} }
if (obj && obj.bareOsExecMaxDepth != null) { if (obj && obj.bareOsExecMaxDepth != null) {
fields.push(discordField('exec depth', String(obj.bareOsExecMaxDepth), true)) fields.push(discordField('Exec depth', String(obj.bareOsExecMaxDepth), true))
} }
return fields return fields
} }
@@ -1305,15 +1381,60 @@ function discordFormatFeatures(obj) {
const keys = Object.keys(feat).sort() const keys = Object.keys(feat).sort()
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
const v = feat[keys[i]] const v = feat[keys[i]]
if (v === true || v === 1 || v === '1') on.push(keys[i]) if (v === true || v === 1 || v === '1') on.push('`' + keys[i] + '`')
else if (v === false || v === 0 || v === '0') off.push(keys[i]) else if (v === false || v === 0 || v === '0') off.push('`' + keys[i] + '`')
} }
const fields = [] const fields = []
if (on.length) fields.push(discordField('Enabled', on.slice(0, 30).join(', '))) if (on.length) fields.push(discordField('On', on.slice(0, 24).join(' ')))
if (off.length) fields.push(discordField('Off', off.slice(0, 20).join(', '))) if (off.length) fields.push(discordField('Off', off.slice(0, 16).join(' ')))
return fields return fields
} }
function discordFormatDoctor(obj) {
if (!obj || typeof obj !== 'object') {
return { fields: [], desc: '', color: BARE_OS_DISCORD_COLOR_WARN }
}
const pa = obj.peerAdmission && typeof obj.peerAdmission === 'object' ? obj.peerAdmission : {}
const hn = obj.hostnameMutation && typeof obj.hostnameMutation === 'object' ? obj.hostnameMutation : {}
const kh = obj.keyHandlePolicy && typeof obj.keyHandlePolicy === 'object' ? obj.keyHandlePolicy : {}
const fields = []
if (pa.allowlistConfigured != null) {
fields.push(discordField('Peer allowlist', pa.allowlistConfigured ? 'configured' : 'open', true))
}
if (pa.denylistConfigured != null) {
fields.push(discordField('Peer denylist', pa.denylistConfigured ? 'configured' : 'none', true))
}
if (pa.requireCapsConfigured != null) {
const n = pa.requireCapsTokenCount
fields.push(
discordField(
'Require caps',
pa.requireCapsConfigured ? (n ? n + ' tokens' : 'yes') : 'no',
true
)
)
}
if (hn.enabled != null) {
fields.push(discordField('Hostname set', hn.enabled ? 'allowed' : 'locked', true))
}
if (kh.defaultTtlMs) {
fields.push(discordField('Key TTL', discordPrettyValue('defaultTtlMs', kh.defaultTtlMs), true))
}
if (Array.isArray(obj.mfaExtensionPoints) && obj.mfaExtensionPoints.length) {
fields.push(discordField('MFA hooks', obj.mfaExtensionPoints.join(' · '), false))
}
const bits = []
if (pa.allowlistConfigured) bits.push('peer allowlist on')
else if (pa.allowlistConfigured === false) bits.push('peer allowlist **open**')
if (hn.enabled === true) bits.push('hostname mutation on')
else if (hn.enabled === false) bits.push('hostname locked')
return {
fields: fields,
desc: bits.join(' · '),
color: pa.allowlistConfigured ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN
}
}
async function discordCmdHandleSys(ctx, sub) { async function discordCmdHandleSys(ctx, sub) {
if (sub === 'df') { if (sub === 'df') {
const t = const t =
@@ -1346,42 +1467,65 @@ async function discordCmdHandleSys(ctx, sub) {
const table = await discordCmdReadJson(ctx, '/proc/bare_os/process_table.json') const table = await discordCmdReadJson(ctx, '/proc/bare_os/process_table.json')
const rows = table && Array.isArray(table.processes) ? table.processes : [] const rows = table && Array.isArray(table.processes) ? table.processes : []
const fields = [] const fields = []
for (let i = 0; i < Math.min(rows.length, 20); i++) { for (let i = 0; i < Math.min(rows.length, 18); i++) {
const r = rows[i] || {} const r = rows[i] || {}
const name = String(r.name || r.comm || r.cmd || r.id || 'proc') const name = String(r.name || r.comm || r.cmd || r.id || 'proc')
const st = String(r.state || r.status || '') const st = String(r.state || r.status || '')
const pid = String(r.pid || r.id || i) const pid = String(r.pid || r.id || i)
fields.push(discordField('#' + pid + ' ' + name, st, true)) fields.push(discordField(name, 'pid ' + pid + (st ? ' · ' + st : ''), true))
} }
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Processes · ' + rows.length, title: 'Processes · ' + rows.length,
desc: rows.length ? '' : 'No logical processes in the session table.', desc: rows.length ? rows.length + ' logical processes in this session.' : 'No logical processes in the session table.',
fields: fields fields: fields
}) })
) )
} }
if (sub === 'env') { if (sub === 'env') {
const e = discordCmdEnv(ctx) const e = discordCmdEnv(ctx)
const ident = [ const fields = [
discordField('USER', e.USER, true), discordField('User', e.USER, true),
discordField('HOME', e.HOME, true), discordField('Home', e.HOME, true),
discordField('SHELL', e.SHELL, true),
discordField('PWD', e.PWD, true),
discordField('Identity', e.BARE_OS_IDENTITY, true), discordField('Identity', e.BARE_OS_IDENTITY, true),
discordField('UID/GID', String(e.UID || '—') + ' / ' + String(e.GID || '—'), true) discordField('Shell', e.SHELL, true),
discordField('Pwd', e.PWD, true),
discordField(
'UID / GID',
e.UID || e.GID ? String(e.UID || '—') + ' / ' + String(e.GID || '—') : '',
true
)
]
const prefer = [
'HOSTNAME',
'PATH',
'TERM',
'TZ',
'LANG',
'EDITOR',
'PAGER',
'BARE_OS_THEME',
'BARE_OS_COLOR_DEPTH'
] ]
const skip = /TOKEN|SECRET|PASSWORD|PASSWD|KEY|PRIVATE|CREDENTIAL|^USER$|^HOME$|^SHELL$|^PWD$|^LOGNAME$|^UID$|^GID$|^GROUP$|^BARE_OS_IDENTITY$/i const skip = /TOKEN|SECRET|PASSWORD|PASSWD|KEY|PRIVATE|CREDENTIAL|^USER$|^HOME$|^SHELL$|^PWD$|^LOGNAME$|^UID$|^GID$|^GROUP$|^BARE_OS_IDENTITY$/i
const rest = [] const seen = Object.create(null)
for (let i = 0; i < prefer.length; i++) {
const k = prefer[i]
seen[k] = 1
if (e[k] == null || e[k] === '') continue
fields.push(discordField(discordHumanLabel(k.replace(/^BARE_OS_/, '')), String(e[k]).slice(0, 80), true))
}
const keys = Object.keys(e).sort() const keys = Object.keys(e).sort()
for (let i = 0; i < keys.length && rest.length < 16; i++) { for (let i = 0; i < keys.length && fields.length < 15; i++) {
if (skip.test(keys[i])) continue if (seen[keys[i]] || skip.test(keys[i])) continue
rest.push(discordField(keys[i], String(e[keys[i]]).slice(0, 80), true)) if (e[keys[i]] == null || e[keys[i]] === '') continue
fields.push(discordField(keys[i], String(e[keys[i]]).slice(0, 72), true))
} }
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Environment · ' + discordSessionUser(ctx), title: 'Environment',
fields: ident.concat(rest) desc: 'Session env for **' + discordSessionUser(ctx) + '** (secrets omitted).',
fields: fields
}), }),
{ ephemeral: true } { ephemeral: true }
) )
@@ -1391,10 +1535,18 @@ async function discordCmdHandleSys(ctx, sub) {
(await discordCmdReadText(ctx, '/proc/bare_os/security_posture.json')) || (await discordCmdReadText(ctx, '/proc/bare_os/security_posture.json')) ||
(await discordCmdReadText(ctx, '/proc/bare_os/debug.json')) (await discordCmdReadText(ctx, '/proc/bare_os/debug.json'))
const obj = discordTryJson(t) const obj = discordTryJson(t)
const pa = obj && obj.peerAdmission const fmt = obj ? discordFormatDoctor(obj) : null
const color = if (fmt && fmt.fields.length) {
pa && pa.allowlistConfigured ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN return discordResult(
return discordPrettySnapshot('Doctor', t, { color: color }) discordEmbed({
title: 'Doctor',
desc: fmt.desc,
fields: fmt.fields,
color: fmt.color
})
)
}
return discordPrettySnapshot('Doctor', t, { color: fmt && fmt.color })
} }
if (sub === 'features') { if (sub === 'features') {
const t = const t =
@@ -1404,7 +1556,13 @@ async function discordCmdHandleSys(ctx, sub) {
const obj = discordTryJson(t) const obj = discordTryJson(t)
const fields = obj ? discordFormatFeatures(obj) : [] const fields = obj ? discordFormatFeatures(obj) : []
if (fields.length) { if (fields.length) {
return discordResult(discordEmbed({ title: 'Features', fields: fields })) return discordResult(
discordEmbed({
title: 'Features',
desc: 'Guest capability flags on this booter.',
fields: fields
})
)
} }
return discordPrettySnapshot('Features', t) return discordPrettySnapshot('Features', t)
} }
@@ -1416,7 +1574,7 @@ async function discordCmdHandleSys(ctx, sub) {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Resource limits', title: 'Resource limits',
desc: 'soft / hard · Bare OS runtime caps (not Linux rlimits)', desc: 'Soft / hard · Bare OS runtime caps (not Linux rlimits).',
fields: fields fields: fields
}) })
) )
@@ -1439,14 +1597,11 @@ async function discordCmdHandleSvc(ctx, sub, unit) {
const fields = [] const fields = []
for (let i = 0; i < parsed.length && fields.length < 20; i++) { for (let i = 0; i < parsed.length && fields.length < 20; i++) {
const r = parsed[i] const r = parsed[i]
const st = (r.active || '—') + (r.sub ? ' / ' + r.sub : '') const bits = []
fields.push( if (r.active) bits.push('**' + r.active + '**')
discordField( if (r.sub && r.sub !== r.active) bits.push(r.sub)
r.unit, if (r.preset && r.preset !== 'enabled') bits.push(r.preset)
st + (r.preset && r.preset !== 'enabled' ? ' · ' + r.preset : ''), fields.push(discordField(r.unit, bits.join(' · ') || 'unknown', true))
true
)
)
} }
const units = await discordSuggestUnits(ctx, '') const units = await discordSuggestUnits(ctx, '')
const sel = discordSelect( const sel = discordSelect(
@@ -1459,7 +1614,11 @@ async function discordCmdHandleSvc(ctx, sub, unit) {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Services · ' + (parsed.length || 0), title: 'Services · ' + (parsed.length || 0),
desc: parsed.length ? '' : out ? discordCmdClip(out, 800) : '(no units)', desc: parsed.length
? 'Pick a unit to inspect, start, or stop.'
: out
? discordCmdClip(out, 800)
: 'No units registered in this session.',
fields: fields, fields: fields,
color: BARE_OS_DISCORD_COLOR color: BARE_OS_DISCORD_COLOR
}), }),
@@ -1491,8 +1650,11 @@ async function discordCmdHandleSvc(ctx, sub, unit) {
discordEmbed({ discordEmbed({
title: name, title: name,
desc: out desc: out
? '**systemctl ' + sub + '**\n' + discordCmdClip(discordCmdRedact(out), 1200) ? '`' +
: '(no output)', sub +
'`\n' +
discordCmdFence(discordCmdClip(discordCmdRedact(out), 1100))
: 'No output from `systemctl ' + sub + '`.',
color: color color: color
}), }),
{ components: act ? [act] : [] } { components: act ? [act] : [] }
@@ -1522,11 +1684,18 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
: '(empty)' : '(empty)'
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'ls ' + p, title: 'Listing',
desc: desc:
'`' +
p +
'` · ' +
list.length +
' ' +
(list.length === 1 ? 'entry' : 'entries') +
'\n' +
desc + desc +
(list.length > shown.length ? '\n+' + (list.length - shown.length) + ' more' : ''), (list.length > shown.length ? '\n+' + (list.length - shown.length) + ' more' : ''),
footer: list.length + ' entries · ' + discordSessionUser(ctx) footer: discordSessionUser(ctx)
}) })
) )
} catch (err) { } catch (err) {
@@ -1555,14 +1724,12 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
discordField('Modified', Number.isFinite(ms) ? new Date(ms).toISOString() : String(st.mtime), true) discordField('Modified', Number.isFinite(ms) ? new Date(ms).toISOString() : String(st.mtime), true)
) )
} }
if (st.path) fields.push(discordField('Path', String(st.path), false)) if (st.path && st.path !== p) fields.push(discordField('Resolved', String(st.path), false))
if (fields.length < 4) {
discordCollectFields(st, '', fields, 0)
}
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'stat ' + p, title: 'Stat',
fields: fields.slice(0, 20) desc: '`' + p + '`',
fields: fields.slice(0, 12)
}) })
) )
} catch (err) { } catch (err) {
@@ -1571,7 +1738,7 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
} }
const text = await discordCmdReadText(ctx, p) const text = await discordCmdReadText(ctx, p)
if (!text) { if (!text) {
return discordResult(discordEmbed({ title: p, desc: '(empty or unreadable)' })) return discordResult(discordEmbed({ title: 'File', desc: '`' + p + '` is empty or unreadable.' }))
} }
const writable = Boolean(discordCmdPathWriteOk(ctx, p)) const writable = Boolean(discordCmdPathWriteOk(ctx, p))
const editRow = writable const editRow = writable
@@ -1583,63 +1750,148 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
} }
const asJson = discordTryJson(text) const asJson = discordTryJson(text)
if (asJson && typeof asJson === 'object' && !Array.isArray(asJson)) { if (asJson && typeof asJson === 'object' && !Array.isArray(asJson)) {
return discordPrettySnapshot((sub === 'head' ? 'head ' : '') + p, asJson, extra) return discordPrettySnapshot(p, asJson, extra)
} }
if (sub === 'head') { if (sub === 'head') {
const n = Math.max(1, Math.min(40, Number(nlines) || 12)) const n = Math.max(1, Math.min(40, Number(nlines) || 12))
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'head ' + p, title: 'Head',
desc: discordCmdFence(text.split(/\r?\n/).slice(0, n).join('\n')) desc: '`' + p + '` · first ' + n + ' lines\n' + discordCmdFence(text.split(/\r?\n/).slice(0, n).join('\n'))
}), }),
extra extra
) )
} }
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: p, title: 'File',
desc: discordCmdFence(text.slice(0, BARE_OS_DISCORD_FS_MAX)), desc: '`' + p + '`\n' + discordCmdFence(text.slice(0, BARE_OS_DISCORD_FS_MAX)),
footer: text.length + ' bytes · ' + discordSessionUser(ctx) footer: text.length + ' bytes · ' + discordSessionUser(ctx)
}), }),
extra extra
) )
} }
function discordFormatNetSummary(obj) {
if (!obj || typeof obj !== 'object') {
return { fields: [], desc: '', color: BARE_OS_DISCORD_COLOR }
}
const rq =
obj.replicationQueue && typeof obj.replicationQueue === 'object' ? obj.replicationQueue : {}
const st = obj.stagingSlot && typeof obj.stagingSlot === 'object' ? obj.stagingSlot : {}
const fields = []
const peers = obj.peerCount
const role = obj.seedRole || rq.role || st.role
const proto = rq.protocol || st.protocol || obj.protocol
if (peers != null) fields.push(discordField('Peers', String(peers), true))
if (role) fields.push(discordField('Role', String(role), true))
if (proto) fields.push(discordField('Protocol', '`' + String(proto) + '`', true))
if (obj.topicHex) {
const hex = String(obj.topicHex)
fields.push(
discordField('Topic', '`' + hex.slice(0, 16) + (hex.length > 16 ? '…' : '') + '`', true)
)
}
if (obj.replicationQueueDepth != null) {
fields.push(discordField('Queue depth', String(obj.replicationQueueDepth), true))
}
if (rq.queueDepthEstimate != null) {
fields.push(discordField('Queue estimate', String(rq.queueDepthEstimate), true))
}
if (rq.hypercoreLengthHint != null) {
fields.push(discordField('Core length', String(rq.hypercoreLengthHint), true))
}
if (rq.manifestPathCount != null) {
fields.push(discordField('Manifests', String(rq.manifestPathCount), true))
}
if (rq.localRamBlockCount != null) {
fields.push(discordField('RAM blocks', String(rq.localRamBlockCount), true))
}
if (st.activeSlot) fields.push(discordField('Active slot', String(st.activeSlot), true))
const fwA = obj.peerFirewallAcceptedTotal
const fwR = obj.peerFirewallRejectedTotal
const fwI = obj.peerFirewallInboundTotal
const fwO = obj.peerFirewallOutboundTotal
if (fwA != null || fwR != null || fwI != null || fwO != null) {
fields.push(
discordField(
'Firewall',
'accept ' +
(fwA == null ? '0' : fwA) +
' · reject ' +
(fwR == null ? '0' : fwR) +
'\nin ' +
(fwI == null ? '0' : fwI) +
' · out ' +
(fwO == null ? '0' : fwO),
true
)
)
}
if (obj.seedHandshakeError) {
fields.push(discordField('Handshake', String(obj.seedHandshakeError), false))
}
const peerN = Number(peers)
const head = []
if (Number.isFinite(peerN)) head.push('**' + peerN + '** peer' + (peerN === 1 ? '' : 's'))
if (role) head.push(String(role))
if (proto) head.push('`' + proto + '`')
let desc = head.join(' · ')
const note = rq.snapshotWorkflowNote || obj.note
if (note) desc += (desc ? '\n' : '') + '*' + String(note).slice(0, 220) + '*'
const at = rq.atMs || obj.atMs
return {
fields: fields,
desc: desc,
color: Number.isFinite(peerN) && peerN > 0 ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN,
footer: at ? 'Updated ' + new Date(Number(at)).toISOString() + ' · expires after 2m idle' : ''
}
}
function discordFormatSwarm(obj) { function discordFormatSwarm(obj) {
if (!obj || typeof obj !== 'object') return [] if (!obj || typeof obj !== 'object') return []
const fields = [] const fields = []
if (obj.peerCount != null) fields.push(discordField('Peers', String(obj.peerCount), true)) if (obj.peerCount != null) fields.push(discordField('Peers', String(obj.peerCount), true))
if (obj.protocol) fields.push(discordField('Protocol', String(obj.protocol), true)) if (obj.protocol) fields.push(discordField('Protocol', '`' + String(obj.protocol) + '`', true))
if (obj.topicCount != null) fields.push(discordField('Topics', String(obj.topicCount), true)) if (obj.topicCount != null) fields.push(discordField('Topics', String(obj.topicCount), true))
if (obj.topicHex) { if (obj.topicHex) {
fields.push(discordField('Topic', String(obj.topicHex).slice(0, 16) + '…', true)) const hex = String(obj.topicHex)
fields.push(
discordField('Topic', '`' + hex.slice(0, 16) + (hex.length > 16 ? '…' : '') + '`', true)
)
} }
const lc = obj.lifecycle const lc = obj.lifecycle
if (lc && typeof lc === 'object') { if (lc && typeof lc === 'object') {
const bits = [] const bits = []
const lk = Object.keys(lc) const lk = Object.keys(lc)
for (let i = 0; i < lk.length && bits.length < 6; i++) { for (let i = 0; i < lk.length && bits.length < 6; i++) {
if (typeof lc[lk[i]] !== 'object') bits.push(lk[i] + ': ' + discordPrettyValue(lk[i], lc[lk[i]])) if (typeof lc[lk[i]] === 'object' || discordValueEmpty(lc[lk[i]])) continue
bits.push('**' + discordHumanLabel(lk[i]) + '** ' + discordPrettyValue(lk[i], lc[lk[i]]))
} }
if (bits.length) fields.push(discordField('Lifecycle', bits.join('\n'), true)) if (bits.length) fields.push(discordField('Lifecycle', bits.join('\n'), false))
} }
const sc = obj.peerScoringAggregates const sc = obj.peerScoringAggregates
if (sc && typeof sc === 'object') { if (sc && typeof sc === 'object') {
const banned = sc.bannedActiveCount
const hi = sc.highLatencyEwmaCount
const low = sc.lowSuccessRateBucketCount
if (banned != null || hi != null || low != null) {
fields.push( fields.push(
discordField( discordField(
'Scoring', 'Scoring',
'banned ' + 'banned ' +
String(sc.bannedActiveCount || 0) + String(banned || 0) +
' · high-lat ' + ' · high-lat ' +
String(sc.highLatencyEwmaCount || 0) + String(hi || 0) +
' · low-ok ' + ' · low-ok ' +
String(sc.lowSuccessRateBucketCount || 0), String(low || 0),
true true
) )
) )
} }
}
if (Array.isArray(obj.peers) && obj.peers.length) { if (Array.isArray(obj.peers) && obj.peers.length) {
fields.push(discordField('Peer rows', String(obj.peers.length), true)) fields.push(discordField('Peer list', String(obj.peers.length), true))
} }
return fields return fields
} }
@@ -1653,9 +1905,14 @@ async function discordCmdHandleNet(ctx, sub) {
const obj = discordTryJson(t) const obj = discordTryJson(t)
const fields = obj ? discordFormatSwarm(obj) : [] const fields = obj ? discordFormatSwarm(obj) : []
if (fields.length) { if (fields.length) {
const n = obj && obj.peerCount
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Swarm', title: 'Swarm',
desc:
n != null
? '**' + n + '** peer' + (Number(n) === 1 ? '' : 's') + (obj.protocol ? ' · `' + obj.protocol + '`' : '')
: '',
fields: fields, fields: fields,
color: obj && obj.peerCount > 0 ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN color: obj && obj.peerCount > 0 ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN
}) })
@@ -1667,7 +1924,21 @@ async function discordCmdHandleNet(ctx, sub) {
(await discordCmdReadText(ctx, '/proc/bare_os/net_summary.json')) || (await discordCmdReadText(ctx, '/proc/bare_os/net_summary.json')) ||
(await discordCmdReadText(ctx, '/proc/net/dev')) (await discordCmdReadText(ctx, '/proc/net/dev'))
const obj = discordTryJson(t) const obj = discordTryJson(t)
if (obj) return discordPrettySnapshot('Network', obj) if (obj) {
const fmt = discordFormatNetSummary(obj)
if (fmt.fields.length) {
return discordResult(
discordEmbed({
title: 'Network',
desc: fmt.desc,
fields: fmt.fields,
color: fmt.color,
footer: fmt.footer || undefined
})
)
}
return discordPrettySnapshot('Network', obj)
}
if (t && t.indexOf('Inter-|') >= 0) { if (t && t.indexOf('Inter-|') >= 0) {
const lines = t.split(/\r?\n/).filter(Boolean) const lines = t.split(/\r?\n/).filter(Boolean)
return discordResult( return discordResult(
@@ -1770,7 +2041,7 @@ async function discordCmdHandleRun(ctx, raw) {
title: '$ ' + key, title: '$ ' + key,
footer: 'ran as ' + discordSessionUser(ctx), footer: 'ran as ' + discordSessionUser(ctx),
desc: out desc: out
? discordCmdClip(discordCmdRedact(out), 1500) ? discordCmdFence(discordCmdClip(discordCmdRedact(out), 1400))
: '(no output, exit ' + String(ctx.exitCode || 0) + ')' : '(no output, exit ' + String(ctx.exitCode || 0) + ')'
}) })
) )
@@ -1793,14 +2064,16 @@ async function discordCmdHandleJournal(ctx, unit) {
.slice(-20) .slice(-20)
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'journal · ' + unit, title: 'Journal · ' + unit,
desc: lines.length desc: lines.length
? lines ? discordCmdFence(
lines
.map(function (ln) { .map(function (ln) {
return discordCmdRedact(ln).slice(0, 180) return discordCmdRedact(ln).slice(0, 180)
}) })
.join('\n') .join('\n')
: '(empty journal)' )
: 'Empty journal for `' + unit + '`.'
}) })
) )
} }
@@ -1814,14 +2087,16 @@ async function discordCmdHandleJournal(ctx, unit) {
.slice(-18) .slice(-18)
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'journal', title: 'Journal',
desc: lines.length desc: lines.length
? lines ? discordCmdFence(
lines
.map(function (ln) { .map(function (ln) {
return discordCmdRedact(ln).slice(0, 180) return discordCmdRedact(ln).slice(0, 180)
}) })
.join('\n') .join('\n')
: '(no journal)' )
: 'No journal in `/var/log/bare-os`.'
}) })
) )
} }
@@ -1836,11 +2111,12 @@ function discordPanel(ctx) {
desc: desc:
'Signed in as **' + 'Signed in as **' +
user + user +
'** · home `' + '** · `' +
(e.HOME || '/home/' + user) + (e.HOME || '/home/' + user) +
'`\nUse the buttons, or slash commands with autocomplete.', '`\nPick a button, or use a slash command.',
fields: [ fields: [
discordField('Identity', e.BARE_OS_IDENTITY || (ctx.identity && ctx.identity.state) || '—', true), discordField('User', user, true),
discordField('Identity', e.BARE_OS_IDENTITY || (ctx.identity && ctx.identity.state) || '', true),
discordField('Host', e.HOSTNAME || 'bare-os', true) discordField('Host', e.HOSTNAME || 'bare-os', true)
] ]
}) })
@@ -3081,10 +3357,10 @@ async function discordSettingsView(ctx, interaction) {
rec.page = pg.page rec.page = pg.page
pages = pg.pages pages = pg.pages
page = pg.page page = pg.page
if (!entries.length) fields.push(discordField('aliases', '(none)')) if (!entries.length) fields.push(discordField('Aliases', 'None defined. Add one from the menu.'))
for (let i = 0; i < pg.slice.length; i++) { for (let i = 0; i < pg.slice.length; i++) {
const e = pg.slice[i] const e = pg.slice[i]
fields.push(discordField((rec.sel === e.name ? '▸ ' : '') + e.name, e.value || '(empty)')) fields.push(discordField((rec.sel === e.name ? '▸ ' : '') + e.name, '`' + (e.value || '') + '`'))
} }
itemOpts = [{ label: 'Add alias', value: 'alias_add', description: 'name=command' }].concat( itemOpts = [{ label: 'Add alias', value: 'alias_add', description: 'name=command' }].concat(
pg.slice.map(function (e) { pg.slice.map(function (e) {
@@ -3103,7 +3379,7 @@ async function discordSettingsView(ctx, interaction) {
fields.push( fields.push(
discordField( discordField(
(rec.sel === spec.id ? '▸ ' : '') + spec.label, (rec.sel === spec.id ? '▸ ' : '') + spec.label,
discordSettingsDisplay(spec, cur) + ' · ' + spec.live '**' + discordSettingsDisplay(spec, cur) + '**\n' + spec.live
) )
) )
} }
@@ -3135,12 +3411,9 @@ async function discordSettingsView(ctx, interaction) {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Settings · ' + meta.label + (pages > 1 ? ' · ' + (page + 1) + '/' + pages : ''), title: 'Settings · ' + meta.label + (pages > 1 ? ' · ' + (page + 1) + '/' + pages : ''),
desc: desc: meta.description + '. Secrets are never shown. Pick a row, then **Edit** or **Toggle**.',
'Live-safe session knobs only. Tokens, API keys, and passwords are never shown or written.\n' +
meta.description +
' — persist to `~/.barerc`, `~/.discord/.env` (non-secret keys), or app JSON.',
fields: fields.slice(0, 20), fields: fields.slice(0, 20),
footer: discordSessionUser(ctx) + ' · pick a setting, then Edit / Toggle' footer: discordSessionUser(ctx) + ' · expires after 2m idle'
}), }),
{ components: [gsel, isel, acts, pageRow].filter(Boolean), nav: false } { components: [gsel, isel, acts, pageRow].filter(Boolean), nav: false }
) )
@@ -4306,7 +4579,9 @@ var bareOsDiscordCommands = {
parseSystemctlList: discordParseSystemctlList, parseSystemctlList: discordParseSystemctlList,
formatRlimits: discordFormatRlimits, formatRlimits: discordFormatRlimits,
formatFeatures: discordFormatFeatures, formatFeatures: discordFormatFeatures,
formatDoctor: discordFormatDoctor,
formatSwarm: discordFormatSwarm, formatSwarm: discordFormatSwarm,
formatNetSummary: discordFormatNetSummary,
formatHostDf: discordFormatHostDf, formatHostDf: discordFormatHostDf,
pathWriteOk: discordCmdPathWriteOk, pathWriteOk: discordCmdPathWriteOk,
editChunks: discordEditChunks, editChunks: discordEditChunks,
@@ -946,15 +946,62 @@ test('proc JSON and systemctl text are parsed into embed fields', (t) => {
RLIMIT_NPROC: { cur: 64, max: 256 } RLIMIT_NPROC: { cur: 64, max: 256 }
} }
}) })
t.ok(lim.some((f) => f.name === 'NOFILE' && /1024/.test(f.value))) t.ok(lim.some((f) => f.name === 'Open files' && /1024/.test(f.value)))
const feat = cmds.formatFeatures({ features: { tuiSdk: true, ircTls: false } }) const feat = cmds.formatFeatures({ features: { tuiSdk: true, ircTls: false } })
t.ok(feat.some((f) => f.name === 'Enabled' && /tuiSdk/.test(f.value))) t.ok(feat.some((f) => f.name === 'On' && /tuiSdk/.test(f.value)))
const doc = cmds.formatDoctor({
peerAdmission: { allowlistConfigured: false, denylistConfigured: false, requireCapsConfigured: false },
hostnameMutation: { enabled: false },
mfaExtensionPoints: ['delegated-signer']
})
t.ok(doc.fields.some((f) => f.name === 'Peer allowlist' && f.value === 'open'))
t.ok(doc.fields.some((f) => f.name === 'Hostname set' && f.value === 'locked'))
t.absent(doc.fields.some((f) => /schema|note|evaluator|api/i.test(f.name)))
const swarm = cmds.formatSwarm({ const swarm = cmds.formatSwarm({
peerCount: 3, peerCount: 3,
protocol: 'bare-os-v1', protocol: 'bare-os-v1',
topicHex: 'abcd'.repeat(16) topicHex: 'abcd'.repeat(16)
}) })
t.ok(swarm.some((f) => f.name === 'Peers' && f.value === '3')) t.ok(swarm.some((f) => f.name === 'Peers' && f.value === '3'))
const net = cmds.formatNetSummary({
schemaVersion: 2,
topicHex: '9863e4407570aabbccddeeff00112233',
peerCount: 1,
seedHandshakeError: null,
seedRole: 'seeder',
replicationQueueDepth: null,
peerFirewallAcceptedTotal: null,
peerFirewallRejectedTotal: null,
peerFirewallInboundTotal: null,
peerFirewallOutboundTotal: null,
replicationQueue: {
role: 'seeder',
protocol: 'bare-os-v1',
manifestPathCount: 448,
localRamBlockCount: 1,
hypercoreLengthHint: 12362,
queueDepthEstimate: 448,
snapshotWorkflowNote: 'Align long replication with corestore-snapshot-style cutover.',
atMs: 1770000000000
},
stagingSlot: {
role: 'seeder',
protocol: 'bare-os-v1',
activeSlot: 'a',
pendingSlot: null,
previousSlot: null,
canarySlot: null,
drainDeadlineMs: null
}
})
t.ok(net.fields.some((f) => f.name === 'Peers' && f.value === '1'))
t.ok(net.fields.some((f) => f.name === 'Role' && f.value === 'seeder'))
t.ok(net.fields.some((f) => f.name === 'Topic' && /9863e4407570aabb/.test(f.value)))
t.ok(net.fields.some((f) => f.name === 'Core length' && f.value === '12362'))
t.ok(net.fields.some((f) => f.name === 'Active slot' && f.value === 'a'))
t.absent(net.fields.some((f) => /peerFirewall|schemaVersion|Handshake|Drain/.test(f.name)))
t.absent(net.fields.some((f) => f.value === '—'))
t.ok(/1.*peer/.test(net.desc) && /seeder/.test(net.desc))
const df = cmds.formatHostDf({ const df = cmds.formatHostDf({
host: { platform: 'darwin', arch: 'arm64', totalmem: 8 * 1024 * 1024 * 1024, freemem: 2 * 1024 * 1024 * 1024 }, host: { platform: 'darwin', arch: 'arm64', totalmem: 8 * 1024 * 1024 * 1024, freemem: 2 * 1024 * 1024 * 1024 },
peers: 1, peers: 1,
@@ -973,6 +1020,9 @@ test('proc JSON and systemctl text are parsed into embed fields', (t) => {
snap.embeds[0].fields.every((f) => String(f.value).charAt(0) !== '{'), snap.embeds[0].fields.every((f) => String(f.value).charAt(0) !== '{'),
'fields are not raw JSON objects' 'fields are not raw JSON objects'
) )
t.ok(snap.embeds[0].fields.some((f) => f.name === 'Platform' && f.value === 'darwin'))
t.ok(snap.embeds[0].fields.some((f) => f.name === 'Nested' && /\*\*A\*\*/.test(f.value)))
t.absent(snap.embeds[0].fields.some((f) => f.name === 'schema' || f.value === '—'))
}) })
test('process.emitWarning polyfill and reply payload avoid Bare throw', (t) => { test('process.emitWarning polyfill and reply payload avoid Bare throw', (t) => {
+397 -122
View File
@@ -502,7 +502,7 @@ function discordPrettyValue(key, val) {
} }
if (typeof val === 'string') { if (typeof val === 'string') {
const t = discordCmdRedact(val) const t = discordCmdRedact(val)
if (/^[0-9a-f]{24,}$/i.test(t)) return t.slice(0, 12) + '…' if (/^[0-9a-f]{24,}$/i.test(t)) return '`' + t.slice(0, 16) + (t.length > 16 ? '…' : '') + '`'
return t.length > 180 ? t.slice(0, 177) + '…' : t return t.length > 180 ? t.slice(0, 177) + '…' : t
} }
if (Array.isArray(val)) { if (Array.isArray(val)) {
@@ -520,36 +520,86 @@ function discordPrettyValue(key, val) {
} }
function discordSkipPrettyKey(k) { function discordSkipPrettyKey(k) {
return /TOKEN|SECRET|PASSWORD|PASSWD|PRIVATE|CREDENTIAL|API_KEY/i.test(k) return /TOKEN|SECRET|PASSWORD|PASSWD|PRIVATE|CREDENTIAL|API_KEY/i.test(k) ||
k === 'note' ||
k === 'schema' ||
k === 'schemaVersion'
}
function discordValueEmpty(val) {
if (val == null) return true
if (val === '') return true
if (val === '—') return true
if (Array.isArray(val) && !val.length) return true
if (typeof val === 'object' && !Array.isArray(val) && !Object.keys(val).length) return true
return false
}
function discordHumanLabel(key) {
const known = {
schemaVersion: 'Schema',
topicHex: 'Topic',
peerCount: 'Peers',
seedHandshakeError: 'Handshake',
seedRole: 'Role',
replicationQueueDepth: 'Queue depth',
replicationQueue: 'Replication',
stagingSlot: 'Staging',
snapshotHints: 'Snapshot',
peerFirewallStats: 'Firewall',
peerFirewallAcceptedTotal: 'Accepted',
peerFirewallRejectedTotal: 'Rejected',
peerFirewallInboundTotal: 'Inbound',
peerFirewallOutboundTotal: 'Outbound',
peerFirewallE2e: 'Firewall e2e',
manifestPathCount: 'Manifests',
localRamBlockCount: 'RAM blocks',
hypercoreLengthHint: 'Core length',
queueDepthEstimate: 'Queue estimate',
snapshotWorkflowNote: 'Note',
activeSlot: 'Active slot',
pendingSlot: 'Pending',
previousSlot: 'Previous',
canarySlot: 'Canary',
drainDeadlineMs: 'Drain',
atMs: 'Updated'
}
if (known[key]) return known[key]
const s = String(key || '')
.replace(/[_-]+/g, ' ')
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
.replace(/\s+/g, ' ')
.trim()
if (!s) return String(key || '')
return s.charAt(0).toUpperCase() + s.slice(1)
} }
function discordCollectFields(obj, prefix, out, depth) { function discordCollectFields(obj, prefix, out, depth) {
if (!obj || typeof obj !== 'object' || Array.isArray(obj) || depth > 2) return if (!obj || typeof obj !== 'object' || Array.isArray(obj) || depth > 2) return
const keys = Object.keys(obj) const keys = Object.keys(obj)
for (let i = 0; i < keys.length && out.length < 25; i++) { for (let i = 0; i < keys.length && out.length < 18; i++) {
const k = keys[i] const k = keys[i]
if (discordSkipPrettyKey(k)) continue if (discordSkipPrettyKey(k)) continue
if (k === 'note' || k === 'schema') continue
const val = obj[k] const val = obj[k]
const label = prefix ? prefix + ' · ' + k : k if (discordValueEmpty(val)) continue
const label = prefix ? prefix + ' · ' + discordHumanLabel(k) : discordHumanLabel(k)
if (val && typeof val === 'object' && !Array.isArray(val) && depth < 2) { if (val && typeof val === 'object' && !Array.isArray(val) && depth < 2) {
const lines = []
const sub = Object.keys(val) const sub = Object.keys(val)
const flat = sub.every(function (sk) { for (let j = 0; j < sub.length && lines.length < 8; j++) {
const sv = val[sk]
return sv == null || typeof sv !== 'object'
})
if (flat && sub.length && sub.length <= 5) {
const parts = []
for (let j = 0; j < sub.length; j++) {
if (discordSkipPrettyKey(sub[j])) continue if (discordSkipPrettyKey(sub[j])) continue
parts.push(sub[j] + ': ' + discordPrettyValue(sub[j], val[sub[j]])) const sv = val[sub[j]]
if (discordValueEmpty(sv)) continue
if (sv && typeof sv === 'object') continue
const pretty = discordPrettyValue(sub[j], sv)
if (pretty === '—' || pretty === '(none)') continue
lines.push('**' + discordHumanLabel(sub[j]) + '** ' + pretty)
} }
if (parts.length) out.push(discordField(label, parts.join('\n'), true)) if (lines.length) out.push(discordField(discordHumanLabel(k), lines.join('\n'), false))
} else { } else {
discordCollectFields(val, label, out, depth + 1) const pretty = discordPrettyValue(k, val)
} if (pretty === '—' || pretty === '(none)') continue
} else { out.push(discordField(label, pretty, true))
out.push(discordField(label, discordPrettyValue(k, val), true))
} }
} }
} }
@@ -615,12 +665,12 @@ function discordPrettySnapshot(title, raw, extras) {
} }
const fields = [] const fields = []
discordCollectFields(parsed, '', fields, 0) discordCollectFields(parsed, '', fields, 0)
const note = typeof parsed.note === 'string' ? parsed.note.slice(0, 350) : '' const note = typeof parsed.note === 'string' ? parsed.note.slice(0, 280) : ''
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: title, title: title,
desc: note, desc: note,
fields: fields.slice(0, 25), fields: fields.slice(0, 18),
color: extras && extras.color color: extras && extras.color
}), }),
extras extras
@@ -750,7 +800,17 @@ function discordEmbed(opts) {
} }
if (o.title) e.title = String(o.title).slice(0, 256) if (o.title) e.title = String(o.title).slice(0, 256)
if (o.desc) e.description = discordCmdClip(discordCmdRedact(o.desc), 1800) if (o.desc) e.description = discordCmdClip(discordCmdRedact(o.desc), 1800)
if (o.fields && o.fields.length) e.fields = o.fields if (o.fields && o.fields.length) {
const fields = []
for (let i = 0; i < o.fields.length && fields.length < 25; i++) {
const f = o.fields[i]
if (!f) continue
const v = String(f.value == null ? '' : f.value).trim()
if (!v || v === '—') continue
fields.push(f)
}
if (fields.length) e.fields = fields
}
if (o.author) e.author = o.author if (o.author) e.author = o.author
return e return e
} }
@@ -1339,7 +1399,7 @@ async function discordFmView(ctx, interaction) {
if (listing.err) desc += '\n' + listing.err if (listing.err) desc += '\n' + listing.err
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Files · ' + discordSessionUser(ctx), title: 'Files',
desc: desc, desc: desc,
fields: fields.slice(0, 20), fields: fields.slice(0, 20),
color: rec.confirm ? BARE_OS_DISCORD_COLOR_ERR : BARE_OS_DISCORD_COLOR, color: rec.confirm ? BARE_OS_DISCORD_COLOR_ERR : BARE_OS_DISCORD_COLOR,
@@ -1435,17 +1495,17 @@ async function discordCmdHandleBare(ctx, sub) {
if (sub === 'help') { if (sub === 'help') {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Command map', title: 'Commands',
desc: 'Running as **' + user + '**. Use the buttons below, or slash commands.',
fields: [ fields: [
discordField('/bare', 'status · whoami · hostname · date · uptime · motd · uname · help'), discordField('/bare', 'Session — status, whoami, hostname, date, uptime, motd, uname'),
discordField('/sys', 'df · mem · ps · env · doctor · features · rlimits'), discordField('/sys', 'Host — disk, memory, processes, env, doctor, features, limits'),
discordField('/svc', 'list · status · start · stop · restart · logs *(unit autocomplete)*'), discordField('/svc', 'Services — list, start, stop, restart, logs'),
discordField('/fs', 'ls · cat · stat · head *(path autocomplete)*'), discordField('/fs', 'Read-only VFS — ls, cat, stat, head'),
discordField('/net', 'peers · swarm · summary'), discordField('/net', 'Swarm — peers, summary'),
discordField( discordField('/files /edit /create', 'Browse and edit files under `~/` and `/tmp`'),
'/files /edit /create /settings /man /run /journal /say /panel /ping', discordField('/settings', 'Live session knobs (theme, shell, Discord, agent, aliases)'),
'Files, settings editor, edit/create, lookups, run, logs' discordField('/run /journal /say /man', 'Allowlisted command, logs, speak, man pages')
)
] ]
}) })
) )
@@ -1455,12 +1515,12 @@ async function discordCmdHandleBare(ctx, sub) {
if (sub === 'whoami') { if (sub === 'whoami') {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'whoami', title: 'Whoami',
color: BARE_OS_DISCORD_COLOR_OK, color: BARE_OS_DISCORD_COLOR_OK,
fields: [ fields: [
discordField('User', user, true), discordField('User', user, true),
discordField('Home', e.HOME || '/home/' + user, true), discordField('Home', '`' + (e.HOME || '/home/' + user) + '`', true),
discordField('Identity', e.BARE_OS_IDENTITY || (ctx.identity && ctx.identity.state) || '', true) discordField('Identity', e.BARE_OS_IDENTITY || (ctx.identity && ctx.identity.state) || '', true)
] ]
}) })
) )
@@ -1468,7 +1528,7 @@ async function discordCmdHandleBare(ctx, sub) {
if (sub === 'hostname') { if (sub === 'hostname') {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'hostname', title: 'Hostname',
desc: '`' + String(e.HOSTNAME || e.NAME || 'bare-os') + '`' desc: '`' + String(e.HOSTNAME || e.NAME || 'bare-os') + '`'
}) })
) )
@@ -1476,8 +1536,8 @@ async function discordCmdHandleBare(ctx, sub) {
if (sub === 'date') { if (sub === 'date') {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'date', title: 'Date',
desc: new Date().toISOString() + '\n' + String(Date()) desc: '`' + new Date().toISOString() + '`'
}) })
) )
} }
@@ -1594,17 +1654,33 @@ function discordFormatRlimits(obj) {
const lim = obj && obj.rlimits && typeof obj.rlimits === 'object' ? obj.rlimits : obj const lim = obj && obj.rlimits && typeof obj.rlimits === 'object' ? obj.rlimits : obj
const fields = [] const fields = []
if (!lim || typeof lim !== 'object') return fields if (!lim || typeof lim !== 'object') return fields
const names = {
NOFILE: 'Open files',
NPROC: 'Processes',
AS: 'Address space',
DATA: 'Data',
STACK: 'Stack',
CORE: 'Core dump',
RSS: 'RSS',
CPU: 'CPU time',
FSIZE: 'File size',
NOVM: 'No VM',
MEMLOCK: 'Locked mem'
}
const keys = Object.keys(lim) const keys = Object.keys(lim)
for (let i = 0; i < keys.length && fields.length < 20; i++) { for (let i = 0; i < keys.length && fields.length < 18; i++) {
const v = lim[keys[i]] const raw = keys[i]
const v = lim[raw]
if (v && typeof v === 'object' && (v.cur != null || v.max != null)) { if (v && typeof v === 'object' && (v.cur != null || v.max != null)) {
const cur = discordIsByteishKey(keys[i]) ? discordPrettyBytes(v.cur) : String(v.cur) const short = raw.replace(/^RLIMIT_/, '')
const max = discordIsByteishKey(keys[i]) ? discordPrettyBytes(v.max) : String(v.max) const label = names[short] || discordHumanLabel(short)
fields.push(discordField(keys[i].replace(/^RLIMIT_/, ''), cur + ' / ' + max, true)) const cur = discordIsByteishKey(raw) ? discordPrettyBytes(v.cur) : String(v.cur)
const max = discordIsByteishKey(raw) ? discordPrettyBytes(v.max) : String(v.max)
fields.push(discordField(label, cur + ' / ' + max, true))
} }
} }
if (obj && obj.bareOsExecMaxDepth != null) { if (obj && obj.bareOsExecMaxDepth != null) {
fields.push(discordField('exec depth', String(obj.bareOsExecMaxDepth), true)) fields.push(discordField('Exec depth', String(obj.bareOsExecMaxDepth), true))
} }
return fields return fields
} }
@@ -1618,15 +1694,60 @@ function discordFormatFeatures(obj) {
const keys = Object.keys(feat).sort() const keys = Object.keys(feat).sort()
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
const v = feat[keys[i]] const v = feat[keys[i]]
if (v === true || v === 1 || v === '1') on.push(keys[i]) if (v === true || v === 1 || v === '1') on.push('`' + keys[i] + '`')
else if (v === false || v === 0 || v === '0') off.push(keys[i]) else if (v === false || v === 0 || v === '0') off.push('`' + keys[i] + '`')
} }
const fields = [] const fields = []
if (on.length) fields.push(discordField('Enabled', on.slice(0, 30).join(', '))) if (on.length) fields.push(discordField('On', on.slice(0, 24).join(' ')))
if (off.length) fields.push(discordField('Off', off.slice(0, 20).join(', '))) if (off.length) fields.push(discordField('Off', off.slice(0, 16).join(' ')))
return fields return fields
} }
function discordFormatDoctor(obj) {
if (!obj || typeof obj !== 'object') {
return { fields: [], desc: '', color: BARE_OS_DISCORD_COLOR_WARN }
}
const pa = obj.peerAdmission && typeof obj.peerAdmission === 'object' ? obj.peerAdmission : {}
const hn = obj.hostnameMutation && typeof obj.hostnameMutation === 'object' ? obj.hostnameMutation : {}
const kh = obj.keyHandlePolicy && typeof obj.keyHandlePolicy === 'object' ? obj.keyHandlePolicy : {}
const fields = []
if (pa.allowlistConfigured != null) {
fields.push(discordField('Peer allowlist', pa.allowlistConfigured ? 'configured' : 'open', true))
}
if (pa.denylistConfigured != null) {
fields.push(discordField('Peer denylist', pa.denylistConfigured ? 'configured' : 'none', true))
}
if (pa.requireCapsConfigured != null) {
const n = pa.requireCapsTokenCount
fields.push(
discordField(
'Require caps',
pa.requireCapsConfigured ? (n ? n + ' tokens' : 'yes') : 'no',
true
)
)
}
if (hn.enabled != null) {
fields.push(discordField('Hostname set', hn.enabled ? 'allowed' : 'locked', true))
}
if (kh.defaultTtlMs) {
fields.push(discordField('Key TTL', discordPrettyValue('defaultTtlMs', kh.defaultTtlMs), true))
}
if (Array.isArray(obj.mfaExtensionPoints) && obj.mfaExtensionPoints.length) {
fields.push(discordField('MFA hooks', obj.mfaExtensionPoints.join(' · '), false))
}
const bits = []
if (pa.allowlistConfigured) bits.push('peer allowlist on')
else if (pa.allowlistConfigured === false) bits.push('peer allowlist **open**')
if (hn.enabled === true) bits.push('hostname mutation on')
else if (hn.enabled === false) bits.push('hostname locked')
return {
fields: fields,
desc: bits.join(' · '),
color: pa.allowlistConfigured ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN
}
}
async function discordCmdHandleSys(ctx, sub) { async function discordCmdHandleSys(ctx, sub) {
if (sub === 'df') { if (sub === 'df') {
const t = const t =
@@ -1659,42 +1780,65 @@ async function discordCmdHandleSys(ctx, sub) {
const table = await discordCmdReadJson(ctx, '/proc/bare_os/process_table.json') const table = await discordCmdReadJson(ctx, '/proc/bare_os/process_table.json')
const rows = table && Array.isArray(table.processes) ? table.processes : [] const rows = table && Array.isArray(table.processes) ? table.processes : []
const fields = [] const fields = []
for (let i = 0; i < Math.min(rows.length, 20); i++) { for (let i = 0; i < Math.min(rows.length, 18); i++) {
const r = rows[i] || {} const r = rows[i] || {}
const name = String(r.name || r.comm || r.cmd || r.id || 'proc') const name = String(r.name || r.comm || r.cmd || r.id || 'proc')
const st = String(r.state || r.status || '') const st = String(r.state || r.status || '')
const pid = String(r.pid || r.id || i) const pid = String(r.pid || r.id || i)
fields.push(discordField('#' + pid + ' ' + name, st, true)) fields.push(discordField(name, 'pid ' + pid + (st ? ' · ' + st : ''), true))
} }
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Processes · ' + rows.length, title: 'Processes · ' + rows.length,
desc: rows.length ? '' : 'No logical processes in the session table.', desc: rows.length ? rows.length + ' logical processes in this session.' : 'No logical processes in the session table.',
fields: fields fields: fields
}) })
) )
} }
if (sub === 'env') { if (sub === 'env') {
const e = discordCmdEnv(ctx) const e = discordCmdEnv(ctx)
const ident = [ const fields = [
discordField('USER', e.USER, true), discordField('User', e.USER, true),
discordField('HOME', e.HOME, true), discordField('Home', e.HOME, true),
discordField('SHELL', e.SHELL, true),
discordField('PWD', e.PWD, true),
discordField('Identity', e.BARE_OS_IDENTITY, true), discordField('Identity', e.BARE_OS_IDENTITY, true),
discordField('UID/GID', String(e.UID || '—') + ' / ' + String(e.GID || '—'), true) discordField('Shell', e.SHELL, true),
discordField('Pwd', e.PWD, true),
discordField(
'UID / GID',
e.UID || e.GID ? String(e.UID || '—') + ' / ' + String(e.GID || '—') : '',
true
)
]
const prefer = [
'HOSTNAME',
'PATH',
'TERM',
'TZ',
'LANG',
'EDITOR',
'PAGER',
'BARE_OS_THEME',
'BARE_OS_COLOR_DEPTH'
] ]
const skip = /TOKEN|SECRET|PASSWORD|PASSWD|KEY|PRIVATE|CREDENTIAL|^USER$|^HOME$|^SHELL$|^PWD$|^LOGNAME$|^UID$|^GID$|^GROUP$|^BARE_OS_IDENTITY$/i const skip = /TOKEN|SECRET|PASSWORD|PASSWD|KEY|PRIVATE|CREDENTIAL|^USER$|^HOME$|^SHELL$|^PWD$|^LOGNAME$|^UID$|^GID$|^GROUP$|^BARE_OS_IDENTITY$/i
const rest = [] const seen = Object.create(null)
for (let i = 0; i < prefer.length; i++) {
const k = prefer[i]
seen[k] = 1
if (e[k] == null || e[k] === '') continue
fields.push(discordField(discordHumanLabel(k.replace(/^BARE_OS_/, '')), String(e[k]).slice(0, 80), true))
}
const keys = Object.keys(e).sort() const keys = Object.keys(e).sort()
for (let i = 0; i < keys.length && rest.length < 16; i++) { for (let i = 0; i < keys.length && fields.length < 15; i++) {
if (skip.test(keys[i])) continue if (seen[keys[i]] || skip.test(keys[i])) continue
rest.push(discordField(keys[i], String(e[keys[i]]).slice(0, 80), true)) if (e[keys[i]] == null || e[keys[i]] === '') continue
fields.push(discordField(keys[i], String(e[keys[i]]).slice(0, 72), true))
} }
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Environment · ' + discordSessionUser(ctx), title: 'Environment',
fields: ident.concat(rest) desc: 'Session env for **' + discordSessionUser(ctx) + '** (secrets omitted).',
fields: fields
}), }),
{ ephemeral: true } { ephemeral: true }
) )
@@ -1704,10 +1848,18 @@ async function discordCmdHandleSys(ctx, sub) {
(await discordCmdReadText(ctx, '/proc/bare_os/security_posture.json')) || (await discordCmdReadText(ctx, '/proc/bare_os/security_posture.json')) ||
(await discordCmdReadText(ctx, '/proc/bare_os/debug.json')) (await discordCmdReadText(ctx, '/proc/bare_os/debug.json'))
const obj = discordTryJson(t) const obj = discordTryJson(t)
const pa = obj && obj.peerAdmission const fmt = obj ? discordFormatDoctor(obj) : null
const color = if (fmt && fmt.fields.length) {
pa && pa.allowlistConfigured ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN return discordResult(
return discordPrettySnapshot('Doctor', t, { color: color }) discordEmbed({
title: 'Doctor',
desc: fmt.desc,
fields: fmt.fields,
color: fmt.color
})
)
}
return discordPrettySnapshot('Doctor', t, { color: fmt && fmt.color })
} }
if (sub === 'features') { if (sub === 'features') {
const t = const t =
@@ -1717,7 +1869,13 @@ async function discordCmdHandleSys(ctx, sub) {
const obj = discordTryJson(t) const obj = discordTryJson(t)
const fields = obj ? discordFormatFeatures(obj) : [] const fields = obj ? discordFormatFeatures(obj) : []
if (fields.length) { if (fields.length) {
return discordResult(discordEmbed({ title: 'Features', fields: fields })) return discordResult(
discordEmbed({
title: 'Features',
desc: 'Guest capability flags on this booter.',
fields: fields
})
)
} }
return discordPrettySnapshot('Features', t) return discordPrettySnapshot('Features', t)
} }
@@ -1729,7 +1887,7 @@ async function discordCmdHandleSys(ctx, sub) {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Resource limits', title: 'Resource limits',
desc: 'soft / hard · Bare OS runtime caps (not Linux rlimits)', desc: 'Soft / hard · Bare OS runtime caps (not Linux rlimits).',
fields: fields fields: fields
}) })
) )
@@ -1752,14 +1910,11 @@ async function discordCmdHandleSvc(ctx, sub, unit) {
const fields = [] const fields = []
for (let i = 0; i < parsed.length && fields.length < 20; i++) { for (let i = 0; i < parsed.length && fields.length < 20; i++) {
const r = parsed[i] const r = parsed[i]
const st = (r.active || '—') + (r.sub ? ' / ' + r.sub : '') const bits = []
fields.push( if (r.active) bits.push('**' + r.active + '**')
discordField( if (r.sub && r.sub !== r.active) bits.push(r.sub)
r.unit, if (r.preset && r.preset !== 'enabled') bits.push(r.preset)
st + (r.preset && r.preset !== 'enabled' ? ' · ' + r.preset : ''), fields.push(discordField(r.unit, bits.join(' · ') || 'unknown', true))
true
)
)
} }
const units = await discordSuggestUnits(ctx, '') const units = await discordSuggestUnits(ctx, '')
const sel = discordSelect( const sel = discordSelect(
@@ -1772,7 +1927,11 @@ async function discordCmdHandleSvc(ctx, sub, unit) {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Services · ' + (parsed.length || 0), title: 'Services · ' + (parsed.length || 0),
desc: parsed.length ? '' : out ? discordCmdClip(out, 800) : '(no units)', desc: parsed.length
? 'Pick a unit to inspect, start, or stop.'
: out
? discordCmdClip(out, 800)
: 'No units registered in this session.',
fields: fields, fields: fields,
color: BARE_OS_DISCORD_COLOR color: BARE_OS_DISCORD_COLOR
}), }),
@@ -1804,8 +1963,11 @@ async function discordCmdHandleSvc(ctx, sub, unit) {
discordEmbed({ discordEmbed({
title: name, title: name,
desc: out desc: out
? '**systemctl ' + sub + '**\n' + discordCmdClip(discordCmdRedact(out), 1200) ? '`' +
: '(no output)', sub +
'`\n' +
discordCmdFence(discordCmdClip(discordCmdRedact(out), 1100))
: 'No output from `systemctl ' + sub + '`.',
color: color color: color
}), }),
{ components: act ? [act] : [] } { components: act ? [act] : [] }
@@ -1835,11 +1997,18 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
: '(empty)' : '(empty)'
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'ls ' + p, title: 'Listing',
desc: desc:
'`' +
p +
'` · ' +
list.length +
' ' +
(list.length === 1 ? 'entry' : 'entries') +
'\n' +
desc + desc +
(list.length > shown.length ? '\n+' + (list.length - shown.length) + ' more' : ''), (list.length > shown.length ? '\n+' + (list.length - shown.length) + ' more' : ''),
footer: list.length + ' entries · ' + discordSessionUser(ctx) footer: discordSessionUser(ctx)
}) })
) )
} catch (err) { } catch (err) {
@@ -1868,14 +2037,12 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
discordField('Modified', Number.isFinite(ms) ? new Date(ms).toISOString() : String(st.mtime), true) discordField('Modified', Number.isFinite(ms) ? new Date(ms).toISOString() : String(st.mtime), true)
) )
} }
if (st.path) fields.push(discordField('Path', String(st.path), false)) if (st.path && st.path !== p) fields.push(discordField('Resolved', String(st.path), false))
if (fields.length < 4) {
discordCollectFields(st, '', fields, 0)
}
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'stat ' + p, title: 'Stat',
fields: fields.slice(0, 20) desc: '`' + p + '`',
fields: fields.slice(0, 12)
}) })
) )
} catch (err) { } catch (err) {
@@ -1884,7 +2051,7 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
} }
const text = await discordCmdReadText(ctx, p) const text = await discordCmdReadText(ctx, p)
if (!text) { if (!text) {
return discordResult(discordEmbed({ title: p, desc: '(empty or unreadable)' })) return discordResult(discordEmbed({ title: 'File', desc: '`' + p + '` is empty or unreadable.' }))
} }
const writable = Boolean(discordCmdPathWriteOk(ctx, p)) const writable = Boolean(discordCmdPathWriteOk(ctx, p))
const editRow = writable const editRow = writable
@@ -1896,63 +2063,148 @@ async function discordCmdHandleFs(ctx, sub, rawPath, nlines) {
} }
const asJson = discordTryJson(text) const asJson = discordTryJson(text)
if (asJson && typeof asJson === 'object' && !Array.isArray(asJson)) { if (asJson && typeof asJson === 'object' && !Array.isArray(asJson)) {
return discordPrettySnapshot((sub === 'head' ? 'head ' : '') + p, asJson, extra) return discordPrettySnapshot(p, asJson, extra)
} }
if (sub === 'head') { if (sub === 'head') {
const n = Math.max(1, Math.min(40, Number(nlines) || 12)) const n = Math.max(1, Math.min(40, Number(nlines) || 12))
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'head ' + p, title: 'Head',
desc: discordCmdFence(text.split(/\r?\n/).slice(0, n).join('\n')) desc: '`' + p + '` · first ' + n + ' lines\n' + discordCmdFence(text.split(/\r?\n/).slice(0, n).join('\n'))
}), }),
extra extra
) )
} }
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: p, title: 'File',
desc: discordCmdFence(text.slice(0, BARE_OS_DISCORD_FS_MAX)), desc: '`' + p + '`\n' + discordCmdFence(text.slice(0, BARE_OS_DISCORD_FS_MAX)),
footer: text.length + ' bytes · ' + discordSessionUser(ctx) footer: text.length + ' bytes · ' + discordSessionUser(ctx)
}), }),
extra extra
) )
} }
function discordFormatNetSummary(obj) {
if (!obj || typeof obj !== 'object') {
return { fields: [], desc: '', color: BARE_OS_DISCORD_COLOR }
}
const rq =
obj.replicationQueue && typeof obj.replicationQueue === 'object' ? obj.replicationQueue : {}
const st = obj.stagingSlot && typeof obj.stagingSlot === 'object' ? obj.stagingSlot : {}
const fields = []
const peers = obj.peerCount
const role = obj.seedRole || rq.role || st.role
const proto = rq.protocol || st.protocol || obj.protocol
if (peers != null) fields.push(discordField('Peers', String(peers), true))
if (role) fields.push(discordField('Role', String(role), true))
if (proto) fields.push(discordField('Protocol', '`' + String(proto) + '`', true))
if (obj.topicHex) {
const hex = String(obj.topicHex)
fields.push(
discordField('Topic', '`' + hex.slice(0, 16) + (hex.length > 16 ? '…' : '') + '`', true)
)
}
if (obj.replicationQueueDepth != null) {
fields.push(discordField('Queue depth', String(obj.replicationQueueDepth), true))
}
if (rq.queueDepthEstimate != null) {
fields.push(discordField('Queue estimate', String(rq.queueDepthEstimate), true))
}
if (rq.hypercoreLengthHint != null) {
fields.push(discordField('Core length', String(rq.hypercoreLengthHint), true))
}
if (rq.manifestPathCount != null) {
fields.push(discordField('Manifests', String(rq.manifestPathCount), true))
}
if (rq.localRamBlockCount != null) {
fields.push(discordField('RAM blocks', String(rq.localRamBlockCount), true))
}
if (st.activeSlot) fields.push(discordField('Active slot', String(st.activeSlot), true))
const fwA = obj.peerFirewallAcceptedTotal
const fwR = obj.peerFirewallRejectedTotal
const fwI = obj.peerFirewallInboundTotal
const fwO = obj.peerFirewallOutboundTotal
if (fwA != null || fwR != null || fwI != null || fwO != null) {
fields.push(
discordField(
'Firewall',
'accept ' +
(fwA == null ? '0' : fwA) +
' · reject ' +
(fwR == null ? '0' : fwR) +
'\nin ' +
(fwI == null ? '0' : fwI) +
' · out ' +
(fwO == null ? '0' : fwO),
true
)
)
}
if (obj.seedHandshakeError) {
fields.push(discordField('Handshake', String(obj.seedHandshakeError), false))
}
const peerN = Number(peers)
const head = []
if (Number.isFinite(peerN)) head.push('**' + peerN + '** peer' + (peerN === 1 ? '' : 's'))
if (role) head.push(String(role))
if (proto) head.push('`' + proto + '`')
let desc = head.join(' · ')
const note = rq.snapshotWorkflowNote || obj.note
if (note) desc += (desc ? '\n' : '') + '*' + String(note).slice(0, 220) + '*'
const at = rq.atMs || obj.atMs
return {
fields: fields,
desc: desc,
color: Number.isFinite(peerN) && peerN > 0 ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN,
footer: at ? 'Updated ' + new Date(Number(at)).toISOString() + ' · expires after 2m idle' : ''
}
}
function discordFormatSwarm(obj) { function discordFormatSwarm(obj) {
if (!obj || typeof obj !== 'object') return [] if (!obj || typeof obj !== 'object') return []
const fields = [] const fields = []
if (obj.peerCount != null) fields.push(discordField('Peers', String(obj.peerCount), true)) if (obj.peerCount != null) fields.push(discordField('Peers', String(obj.peerCount), true))
if (obj.protocol) fields.push(discordField('Protocol', String(obj.protocol), true)) if (obj.protocol) fields.push(discordField('Protocol', '`' + String(obj.protocol) + '`', true))
if (obj.topicCount != null) fields.push(discordField('Topics', String(obj.topicCount), true)) if (obj.topicCount != null) fields.push(discordField('Topics', String(obj.topicCount), true))
if (obj.topicHex) { if (obj.topicHex) {
fields.push(discordField('Topic', String(obj.topicHex).slice(0, 16) + '…', true)) const hex = String(obj.topicHex)
fields.push(
discordField('Topic', '`' + hex.slice(0, 16) + (hex.length > 16 ? '…' : '') + '`', true)
)
} }
const lc = obj.lifecycle const lc = obj.lifecycle
if (lc && typeof lc === 'object') { if (lc && typeof lc === 'object') {
const bits = [] const bits = []
const lk = Object.keys(lc) const lk = Object.keys(lc)
for (let i = 0; i < lk.length && bits.length < 6; i++) { for (let i = 0; i < lk.length && bits.length < 6; i++) {
if (typeof lc[lk[i]] !== 'object') bits.push(lk[i] + ': ' + discordPrettyValue(lk[i], lc[lk[i]])) if (typeof lc[lk[i]] === 'object' || discordValueEmpty(lc[lk[i]])) continue
bits.push('**' + discordHumanLabel(lk[i]) + '** ' + discordPrettyValue(lk[i], lc[lk[i]]))
} }
if (bits.length) fields.push(discordField('Lifecycle', bits.join('\n'), true)) if (bits.length) fields.push(discordField('Lifecycle', bits.join('\n'), false))
} }
const sc = obj.peerScoringAggregates const sc = obj.peerScoringAggregates
if (sc && typeof sc === 'object') { if (sc && typeof sc === 'object') {
const banned = sc.bannedActiveCount
const hi = sc.highLatencyEwmaCount
const low = sc.lowSuccessRateBucketCount
if (banned != null || hi != null || low != null) {
fields.push( fields.push(
discordField( discordField(
'Scoring', 'Scoring',
'banned ' + 'banned ' +
String(sc.bannedActiveCount || 0) + String(banned || 0) +
' · high-lat ' + ' · high-lat ' +
String(sc.highLatencyEwmaCount || 0) + String(hi || 0) +
' · low-ok ' + ' · low-ok ' +
String(sc.lowSuccessRateBucketCount || 0), String(low || 0),
true true
) )
) )
} }
}
if (Array.isArray(obj.peers) && obj.peers.length) { if (Array.isArray(obj.peers) && obj.peers.length) {
fields.push(discordField('Peer rows', String(obj.peers.length), true)) fields.push(discordField('Peer list', String(obj.peers.length), true))
} }
return fields return fields
} }
@@ -1966,9 +2218,14 @@ async function discordCmdHandleNet(ctx, sub) {
const obj = discordTryJson(t) const obj = discordTryJson(t)
const fields = obj ? discordFormatSwarm(obj) : [] const fields = obj ? discordFormatSwarm(obj) : []
if (fields.length) { if (fields.length) {
const n = obj && obj.peerCount
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Swarm', title: 'Swarm',
desc:
n != null
? '**' + n + '** peer' + (Number(n) === 1 ? '' : 's') + (obj.protocol ? ' · `' + obj.protocol + '`' : '')
: '',
fields: fields, fields: fields,
color: obj && obj.peerCount > 0 ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN color: obj && obj.peerCount > 0 ? BARE_OS_DISCORD_COLOR_OK : BARE_OS_DISCORD_COLOR_WARN
}) })
@@ -1980,7 +2237,21 @@ async function discordCmdHandleNet(ctx, sub) {
(await discordCmdReadText(ctx, '/proc/bare_os/net_summary.json')) || (await discordCmdReadText(ctx, '/proc/bare_os/net_summary.json')) ||
(await discordCmdReadText(ctx, '/proc/net/dev')) (await discordCmdReadText(ctx, '/proc/net/dev'))
const obj = discordTryJson(t) const obj = discordTryJson(t)
if (obj) return discordPrettySnapshot('Network', obj) if (obj) {
const fmt = discordFormatNetSummary(obj)
if (fmt.fields.length) {
return discordResult(
discordEmbed({
title: 'Network',
desc: fmt.desc,
fields: fmt.fields,
color: fmt.color,
footer: fmt.footer || undefined
})
)
}
return discordPrettySnapshot('Network', obj)
}
if (t && t.indexOf('Inter-|') >= 0) { if (t && t.indexOf('Inter-|') >= 0) {
const lines = t.split(/\r?\n/).filter(Boolean) const lines = t.split(/\r?\n/).filter(Boolean)
return discordResult( return discordResult(
@@ -2083,7 +2354,7 @@ async function discordCmdHandleRun(ctx, raw) {
title: '$ ' + key, title: '$ ' + key,
footer: 'ran as ' + discordSessionUser(ctx), footer: 'ran as ' + discordSessionUser(ctx),
desc: out desc: out
? discordCmdClip(discordCmdRedact(out), 1500) ? discordCmdFence(discordCmdClip(discordCmdRedact(out), 1400))
: '(no output, exit ' + String(ctx.exitCode || 0) + ')' : '(no output, exit ' + String(ctx.exitCode || 0) + ')'
}) })
) )
@@ -2106,14 +2377,16 @@ async function discordCmdHandleJournal(ctx, unit) {
.slice(-20) .slice(-20)
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'journal · ' + unit, title: 'Journal · ' + unit,
desc: lines.length desc: lines.length
? lines ? discordCmdFence(
lines
.map(function (ln) { .map(function (ln) {
return discordCmdRedact(ln).slice(0, 180) return discordCmdRedact(ln).slice(0, 180)
}) })
.join('\n') .join('\n')
: '(empty journal)' )
: 'Empty journal for `' + unit + '`.'
}) })
) )
} }
@@ -2127,14 +2400,16 @@ async function discordCmdHandleJournal(ctx, unit) {
.slice(-18) .slice(-18)
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'journal', title: 'Journal',
desc: lines.length desc: lines.length
? lines ? discordCmdFence(
lines
.map(function (ln) { .map(function (ln) {
return discordCmdRedact(ln).slice(0, 180) return discordCmdRedact(ln).slice(0, 180)
}) })
.join('\n') .join('\n')
: '(no journal)' )
: 'No journal in `/var/log/bare-os`.'
}) })
) )
} }
@@ -2149,11 +2424,12 @@ function discordPanel(ctx) {
desc: desc:
'Signed in as **' + 'Signed in as **' +
user + user +
'** · home `' + '** · `' +
(e.HOME || '/home/' + user) + (e.HOME || '/home/' + user) +
'`\nUse the buttons, or slash commands with autocomplete.', '`\nPick a button, or use a slash command.',
fields: [ fields: [
discordField('Identity', e.BARE_OS_IDENTITY || (ctx.identity && ctx.identity.state) || '—', true), discordField('User', user, true),
discordField('Identity', e.BARE_OS_IDENTITY || (ctx.identity && ctx.identity.state) || '', true),
discordField('Host', e.HOSTNAME || 'bare-os', true) discordField('Host', e.HOSTNAME || 'bare-os', true)
] ]
}) })
@@ -3394,10 +3670,10 @@ async function discordSettingsView(ctx, interaction) {
rec.page = pg.page rec.page = pg.page
pages = pg.pages pages = pg.pages
page = pg.page page = pg.page
if (!entries.length) fields.push(discordField('aliases', '(none)')) if (!entries.length) fields.push(discordField('Aliases', 'None defined. Add one from the menu.'))
for (let i = 0; i < pg.slice.length; i++) { for (let i = 0; i < pg.slice.length; i++) {
const e = pg.slice[i] const e = pg.slice[i]
fields.push(discordField((rec.sel === e.name ? '▸ ' : '') + e.name, e.value || '(empty)')) fields.push(discordField((rec.sel === e.name ? '▸ ' : '') + e.name, '`' + (e.value || '') + '`'))
} }
itemOpts = [{ label: 'Add alias', value: 'alias_add', description: 'name=command' }].concat( itemOpts = [{ label: 'Add alias', value: 'alias_add', description: 'name=command' }].concat(
pg.slice.map(function (e) { pg.slice.map(function (e) {
@@ -3416,7 +3692,7 @@ async function discordSettingsView(ctx, interaction) {
fields.push( fields.push(
discordField( discordField(
(rec.sel === spec.id ? '▸ ' : '') + spec.label, (rec.sel === spec.id ? '▸ ' : '') + spec.label,
discordSettingsDisplay(spec, cur) + ' · ' + spec.live '**' + discordSettingsDisplay(spec, cur) + '**\n' + spec.live
) )
) )
} }
@@ -3448,12 +3724,9 @@ async function discordSettingsView(ctx, interaction) {
return discordResult( return discordResult(
discordEmbed({ discordEmbed({
title: 'Settings · ' + meta.label + (pages > 1 ? ' · ' + (page + 1) + '/' + pages : ''), title: 'Settings · ' + meta.label + (pages > 1 ? ' · ' + (page + 1) + '/' + pages : ''),
desc: desc: meta.description + '. Secrets are never shown. Pick a row, then **Edit** or **Toggle**.',
'Live-safe session knobs only. Tokens, API keys, and passwords are never shown or written.\n' +
meta.description +
' — persist to `~/.barerc`, `~/.discord/.env` (non-secret keys), or app JSON.',
fields: fields.slice(0, 20), fields: fields.slice(0, 20),
footer: discordSessionUser(ctx) + ' · pick a setting, then Edit / Toggle' footer: discordSessionUser(ctx) + ' · expires after 2m idle'
}), }),
{ components: [gsel, isel, acts, pageRow].filter(Boolean), nav: false } { components: [gsel, isel, acts, pageRow].filter(Boolean), nav: false }
) )
@@ -4619,7 +4892,9 @@ var bareOsDiscordCommands = {
parseSystemctlList: discordParseSystemctlList, parseSystemctlList: discordParseSystemctlList,
formatRlimits: discordFormatRlimits, formatRlimits: discordFormatRlimits,
formatFeatures: discordFormatFeatures, formatFeatures: discordFormatFeatures,
formatDoctor: discordFormatDoctor,
formatSwarm: discordFormatSwarm, formatSwarm: discordFormatSwarm,
formatNetSummary: discordFormatNetSummary,
formatHostDf: discordFormatHostDf, formatHostDf: discordFormatHostDf,
pathWriteOk: discordCmdPathWriteOk, pathWriteOk: discordCmdPathWriteOk,
editChunks: discordEditChunks, editChunks: discordEditChunks,
@@ -1,7 +1,7 @@
{ {
"schema": 2, "schema": 2,
"profileId": "bare-os-posix-like", "profileId": "bare-os-posix-like",
"generatedAt": "2026-08-13T18:01:27.382Z", "generatedAt": "2026-08-13T18:10:42.974Z",
"note": "Sparse POSIX Issue 7 coverage hints; commandIndex is generated each coreutils build.", "note": "Sparse POSIX Issue 7 coverage hints; commandIndex is generated each coreutils build.",
"commandIndex": [ "commandIndex": [
{ {
@@ -1,6 +1,6 @@
{ {
"schema": 1, "schema": 1,
"atMs": 1786644087376, "atMs": 1786644642972,
"commands": [ "commands": [
"agent", "agent",
"appctl", "appctl",
File diff suppressed because one or more lines are too long