fix(swarmtop): expose and render full peer identity/details from proc surfaces

This commit is contained in:
Raven Scott
2026-04-26 08:02:37 -04:00
parent 8c3d5f8795
commit 194fbd2c67
69 changed files with 13463 additions and 32 deletions
+16
View File
@@ -0,0 +1,16 @@
async function run(ctx, argv) {
const argv0 = argv[0] || 'dhtscan'
const args = argv.slice(1)
if (args.includes('-h') || args.includes('--help')) {
ctx.console.log(
'usage: ' +
argv0 +
'\n' +
'Print compact DHT scan summary from /proc/bare_os/dht_scan.json.\n' +
'See man dhtscan.'
)
return
}
const dht = await bareP2pReadProcJson(ctx, '/proc/bare_os/dht_scan.json')
ctx.console.log(JSON.stringify(dht, null, 2))
}
+34
View File
@@ -0,0 +1,34 @@
async function run(ctx, argv) {
const argv0 = argv[0] || 'dhttop'
const args = argv.slice(1)
if (args.includes('-h') || args.includes('--help')) {
ctx.console.log(
'usage: ' + argv0 + '\n' + 'Live DHT dashboard TUI.\n' + 'See man dhttop.'
)
return
}
const stdin = ctx.replStdin
const isTTY = Boolean(stdin && /** @type {{ isTTY?: boolean }} */ (stdin).isTTY)
if (!isTTY) {
const dht = await bareP2pReadProcJson(ctx, '/proc/bare_os/dht_scan.json')
ctx.console.log(JSON.stringify(dht, null, 2))
return
}
await bareP2pRunSimpleTui(ctx, {
title: 'dhttop',
subtitle: 'dht operations · q quit · r refresh',
renderLines: async () => {
const dht = await bareP2pReadProcJson(ctx, '/proc/bare_os/dht_scan.json')
const lines = []
lines.push('schema: ' + String(dht.schema ?? '?'))
lines.push('peers: ' + String(dht.peers ?? '?'))
lines.push('firewalled: ' + String(dht.dhtStatus?.firewalled ?? '?'))
lines.push('randomized: ' + String(dht.dhtStatus?.randomized ?? '?'))
lines.push('bootstrap: ' + String(dht.bootstrapHint || '(default)'))
lines.push('')
lines.push('raw:')
lines.push(JSON.stringify(dht))
return lines
}
})
}
@@ -0,0 +1,35 @@
async function run(ctx, argv) {
const argv0 = argv[0] || 'holepunch-view'
const args = argv.slice(1)
if (args.includes('-h') || args.includes('--help')) {
ctx.console.log(
'usage: ' +
argv0 +
'\n' +
'NAT and holepunch summary dashboard.\n' +
'See man holepunch-view.'
)
return
}
const stdin = ctx.replStdin
const isTTY = Boolean(stdin && /** @type {{ isTTY?: boolean }} */ (stdin).isTTY)
if (!isTTY) {
const h = await bareP2pReadProcJson(ctx, '/proc/bare_os/holepunch_summary.json')
ctx.console.log(JSON.stringify(h, null, 2))
return
}
await bareP2pRunSimpleTui(ctx, {
title: 'holepunch-view',
subtitle: 'nat and holepunch telemetry · q quit · r refresh',
renderLines: async () => {
const h = await bareP2pReadProcJson(ctx, '/proc/bare_os/holepunch_summary.json')
return [
'peers: ' + String(h.peers ?? '?'),
'firewalled: ' + String(h.firewalled ?? '?'),
'randomized: ' + String(h.randomized ?? '?'),
'',
'note: ' + String(h.note || '')
]
}
})
}
+36
View File
@@ -0,0 +1,36 @@
async function run(ctx, argv) {
const argv0 = argv[0] || 'p2ping'
const args = argv.slice(1)
if (args.includes('-h') || args.includes('--help')) {
ctx.console.log(
'usage: ' +
argv0 +
' [LABEL]\n' +
'Emit a p2p ping event and print local swarm timing hints.\n' +
'See man p2ping.'
)
return
}
const label = args.join(' ').trim() || 'ping'
const t0 = Date.now()
const swarm = await bareP2pReadSwarmSnapshot(ctx)
const evtId = bareP2pId('p2ping')
const send = bareP2pSend(ctx, 'p2ping', 'ping', {
evtId,
label,
sentAtMs: t0
})
const t1 = Date.now()
const out = {
schema: 1,
tool: argv0,
evtId,
label,
ok: !(send && send.ok === false),
sendReason: send && send.ok === false ? String(send.reason || 'send_failed') : null,
localElapsedMs: t1 - t0,
swarmPeers: swarm.peerCount
}
ctx.console.log(JSON.stringify(out, null, 2))
if (send && send.ok === false) ctx.exitCode = 1
}
@@ -0,0 +1,45 @@
async function run(ctx, argv) {
const argv0 = argv[0] || 'p2ptrace'
const args = argv.slice(1)
if (args.includes('-h') || args.includes('--help')) {
ctx.console.log(
'usage: ' +
argv0 +
' [APP] [N]\n' +
'Dump recent p2p events as JSON lines.\n' +
'APP defaults to all known p2p apps.\n' +
'See man p2ptrace.'
)
return
}
const app = String(args[0] || '').trim()
const n = Math.max(1, Math.min(2000, parseInt(args[1] || '200', 10) || 200))
const apps = app
? [app]
: [
'swarmtop',
'meshdrop',
'taskmesh',
'peernote',
'hypershell-board',
'p2ping',
'peerdiscover',
'peerctl'
]
const rows = []
for (const a of apps) {
rows.push(...bareP2pCollectFromHistory(ctx, a, n))
}
rows.sort((a, b) => (a.receivedAtMs || 0) - (b.receivedAtMs || 0))
for (const r of rows.slice(-n)) {
ctx.console.log(
JSON.stringify({
atMs: r.receivedAtMs || 0,
app: r.packet?.app || '?',
kind: r.packet?.kind || '?',
from: r.displayName || r.fromPeerKey || '',
payload: r.packet?.payload || {}
})
)
}
}
+81
View File
@@ -0,0 +1,81 @@
async function run(ctx, argv) {
const argv0 = argv[0] || 'peerctl'
const args = argv.slice(1)
if (args.includes('-h') || args.includes('--help') || args.length === 0) {
ctx.console.log(
'usage: ' +
argv0 +
' health\n' +
' ' +
argv0 +
' request ACTION [JSON_PAYLOAD]\n' +
' ' +
argv0 +
' history [N]\n' +
'P2P control plane helper over event envelopes.\n' +
'See man peerctl.'
)
if (args.length === 0) ctx.exitCode = 1
return
}
const sub = args[0]
if (sub === 'health') {
const swarm = await bareP2pReadSwarmSnapshot(ctx)
const doctor = await bareP2pReadProcJson(ctx, '/proc/bare_os/swarm_doctor.json')
ctx.console.log(
JSON.stringify(
{
schema: 1,
swarmPeers: swarm.peerCount,
health: doctor.health || 'unknown',
remediation: doctor.remediation || []
},
null,
2
)
)
return
}
if (sub === 'request') {
const action = String(args[1] || '').trim()
if (!action) {
ctx.console.error(argv0 + ': request requires ACTION')
ctx.exitCode = 1
return
}
let payload = {}
if (args[2]) {
try {
payload = JSON.parse(args.slice(2).join(' '))
} catch {
ctx.console.error(argv0 + ': invalid JSON payload')
ctx.exitCode = 1
return
}
}
const r = bareP2pSend(ctx, 'peerctl', 'request', {
requestId: bareP2pId('ctl'),
action,
payload
})
if (r && r.ok === false) ctx.exitCode = 1
return
}
if (sub === 'history') {
const n = Math.max(1, Math.min(1000, parseInt(args[1] || '50', 10) || 50))
const rows = bareP2pCollectFromHistory(ctx, 'peerctl', 2000).slice(-n)
for (const row of rows) {
ctx.console.log(
'[' +
bareP2pFmtClock(row.receivedAtMs) +
'] ' +
String(row.packet?.kind || '?') +
' ' +
JSON.stringify(row.packet?.payload || {})
)
}
return
}
ctx.console.error(argv0 + ': unsupported subcommand')
ctx.exitCode = 1
}
@@ -0,0 +1,54 @@
async function run(ctx, argv) {
const argv0 = argv[0] || 'peerdiscover'
const args = argv.slice(1)
if (args.includes('-h') || args.includes('--help') || args.length === 0) {
ctx.console.log(
'usage: ' +
argv0 +
' announce SERVICE [META]\n' +
' ' +
argv0 +
' list [N]\n' +
'Peer service announce/list over p2p event history.\n' +
'See man peerdiscover.'
)
if (args.length === 0) ctx.exitCode = 1
return
}
const sub = args[0]
if (sub === 'announce') {
const service = String(args[1] || '').trim()
if (!service) {
ctx.console.error(argv0 + ': announce requires SERVICE')
ctx.exitCode = 1
return
}
const meta = args.slice(2).join(' ').trim()
const r = bareP2pSend(ctx, 'peerdiscover', 'service.announce', {
service,
meta,
id: bareP2pId('svc')
})
if (r && r.ok === false) ctx.exitCode = 1
return
}
if (sub === 'list') {
const n = Math.max(1, Math.min(500, parseInt(args[1] || '50', 10) || 50))
const rows = bareP2pCollectFromHistory(ctx, 'peerdiscover', 2000)
.filter((r) => r.packet?.kind === 'service.announce')
.slice(-n)
for (const row of rows) {
const p = row.packet?.payload || {}
ctx.console.log(
'[' +
bareP2pFmtClock(row.receivedAtMs) +
'] ' +
String(p.service || 'unknown') +
(p.meta ? ' ' + String(p.meta) : '')
)
}
return
}
ctx.console.error(argv0 + ': unsupported subcommand')
ctx.exitCode = 1
}
@@ -0,0 +1,31 @@
async function run(ctx, argv) {
const argv0 = argv[0] || 'routeview'
const args = argv.slice(1)
if (args.includes('-h') || args.includes('--help')) {
ctx.console.log(
'usage: ' + argv0 + '\n' + 'Route and relay visibility TUI.\n' + 'See man routeview.'
)
return
}
const stdin = ctx.replStdin
const isTTY = Boolean(stdin && /** @type {{ isTTY?: boolean }} */ (stdin).isTTY)
if (!isTTY) {
const r = await bareP2pReadProcJson(ctx, '/proc/bare_os/route_summary.json')
ctx.console.log(JSON.stringify(r, null, 2))
return
}
await bareP2pRunSimpleTui(ctx, {
title: 'routeview',
subtitle: 'direct vs relay summary · q quit · r refresh',
renderLines: async () => {
const r = await bareP2pReadProcJson(ctx, '/proc/bare_os/route_summary.json')
return [
'peers: ' + String(r.peers ?? '?'),
'directLikely: ' + String(r.directLikely ?? '?'),
'relayLikely: ' + String(r.relayLikely ?? '?'),
'',
'note: ' + String(r.note || '')
]
}
})
}
@@ -0,0 +1,19 @@
async function run(ctx, argv) {
const argv0 = argv[0] || 'swarmdoctor'
const args = argv.slice(1)
if (args.includes('-h') || args.includes('--help')) {
ctx.console.log(
'usage: ' +
argv0 +
'\n' +
'Print swarm diagnosis from /proc/bare_os/swarm_doctor.json.\n' +
'See man swarmdoctor.'
)
return
}
const doc = await bareP2pReadProcJson(ctx, '/proc/bare_os/swarm_doctor.json')
ctx.console.log(JSON.stringify(doc, null, 2))
if (doc && typeof doc === 'object' && doc.health && doc.health !== 'ok') {
ctx.exitCode = 1
}
}
@@ -0,0 +1,39 @@
async function run(ctx, argv) {
const argv0 = argv[0] || 'swarmmap'
const args = argv.slice(1)
if (args.includes('-h') || args.includes('--help')) {
ctx.console.log(
'usage: ' + argv0 + '\n' + 'Swarm topology map TUI.\n' + 'See man swarmmap.'
)
return
}
const stdin = ctx.replStdin
const isTTY = Boolean(stdin && /** @type {{ isTTY?: boolean }} */ (stdin).isTTY)
const snap = await bareP2pReadSwarmSnapshot(ctx)
if (!isTTY) {
ctx.console.log(JSON.stringify(snap, null, 2))
return
}
await bareP2pRunSimpleTui(ctx, {
title: 'swarmmap',
subtitle: 'peer topology · q quit · r refresh',
renderLines: async () => {
const s = await bareP2pReadSwarmSnapshot(ctx)
const lines = []
lines.push('peerCount: ' + String(s.peerCount ?? '?'))
lines.push('topicCount: ' + String(s.topicCount ?? '?'))
lines.push('')
lines.push('Peers:')
const peers = Array.isArray(s.peers) ? s.peers : []
if (!peers.length) lines.push(' (none)')
for (const p of peers.slice(0, 48)) {
const id =
p && typeof p === 'object' && typeof p.remotePublicKey === 'string'
? p.remotePublicKey.slice(0, 20)
: '?'
lines.push(' ' + id + ' ' + String(p.state || 'connected'))
}
return lines
}
})
}
+18 -3
View File
@@ -85,16 +85,31 @@ async function run(ctx, argv) {
lines.push('Peers:')
const peers = Array.isArray(snap.peers) ? snap.peers : []
if (!peers.length) lines.push(' (no peers reported)')
for (const p of peers.slice(0, 24)) {
for (const p of peers.slice(0, 12)) {
const key =
p && typeof p === 'object' && typeof p.remotePublicKey === 'string'
? p.remotePublicKey.slice(0, 16)
? p.remotePublicKey
: '?'
const state =
p && typeof p === 'object' && typeof p.state === 'string'
? p.state
: 'connected'
lines.push(' ' + key + ' ' + state)
const addr =
p && typeof p === 'object' && p.endpoint && typeof p.endpoint === 'object'
? String(p.endpoint.address || p.remoteAddress || '?') +
':' +
String(p.endpoint.port || p.remotePort || '?')
: String(p?.remoteAddress || '?') + ':' + String(p?.remotePort || '?')
const osHint =
p &&
typeof p === 'object' &&
p.peerOs &&
typeof p.peerOs === 'object' &&
p.peerOs.osHint
? String(p.peerOs.osHint)
: 'unknown'
lines.push(' pubkey: ' + key)
lines.push(' state=' + state + ' endpoint=' + addr + ' os=' + osHint)
}
lines.push('')
lines.push('Recent events:')