feat(p2p): introduce shared p2p transport/service stack and launch swarmtop, meshdrop, taskmesh, peernote, and hypershell-board
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
function bareP2pFmtClock(ms) {
|
||||
const d = new Date(typeof ms === 'number' ? ms : Date.now())
|
||||
const z = (n) => (n < 10 ? '0' : '') + n
|
||||
return z(d.getHours()) + ':' + z(d.getMinutes()) + ':' + z(d.getSeconds())
|
||||
}
|
||||
|
||||
function bareP2pTruncate(s, cols) {
|
||||
const t = String(s || '')
|
||||
if (t.length <= cols) return t
|
||||
return t.slice(0, Math.max(0, cols - 1)) + '\u2026'
|
||||
}
|
||||
|
||||
/**
|
||||
* Read-only TUI shell: q quits, r refreshes.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {{ title: string, subtitle?: string, renderLines: () => string[] | Promise<string[]>, onRefresh?: () => void | Promise<void> }} opts
|
||||
*/
|
||||
async function bareP2pRunSimpleTui(ctx, opts) {
|
||||
const stdin = ctx.replStdin
|
||||
const stdout = bareEditResolveStdout(ctx)
|
||||
if (!stdin || !stdout) {
|
||||
ctx.console.error('p2p tui: missing stdin/stdout')
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
const useColor = bareEditUseColor(ctx)
|
||||
const envEarly =
|
||||
ctx.env && typeof ctx.env === 'object'
|
||||
? /** @type {Record<string, string>} */ (ctx.env)
|
||||
: {}
|
||||
const cols0 = parseInt(envEarly.COLUMNS || '80', 10) || 80
|
||||
const rows0 = parseInt(envEarly.LINES || '24', 10) || 24
|
||||
const dims = () => ({
|
||||
cols:
|
||||
Math.max(48, /** @type {{ columns?: number }} */ (stdout).columns || cols0),
|
||||
rows: Math.max(12, /** @type {{ rows?: number }} */ (stdout).rows || rows0)
|
||||
})
|
||||
|
||||
const reader = bareEditCreateStdinReader(stdin)
|
||||
let suspended = false
|
||||
let alt = false
|
||||
let loop = true
|
||||
|
||||
const draw = async () => {
|
||||
const { cols, rows } = dims()
|
||||
const lines = await opts.renderLines()
|
||||
let out = '\x1b[?25l\x1b[2J\x1b[H'
|
||||
const top =
|
||||
bareEditSgr('status', useColor) +
|
||||
bareP2pTruncate(' ' + opts.title + ' ', cols) +
|
||||
EDIT_ANSI_RESET
|
||||
out += bareEditCup(1, 1) + '\x1b[K' + top
|
||||
const sub = bareP2pTruncate(
|
||||
(opts.subtitle || 'q quit · r refresh') + ' · ' + bareP2pFmtClock(Date.now()),
|
||||
cols
|
||||
)
|
||||
out +=
|
||||
bareEditCup(2, 1) +
|
||||
'\x1b[K' +
|
||||
bareEditSgr('dim', useColor) +
|
||||
sub +
|
||||
EDIT_ANSI_RESET
|
||||
out += bareEditCup(3, 1) + '\x1b[K'
|
||||
const maxBody = Math.max(1, rows - 3)
|
||||
for (let i = 0; i < maxBody; i++) {
|
||||
const raw = i < lines.length ? String(lines[i]) : ''
|
||||
out += bareEditCup(4 + i, 1) + '\x1b[K' + bareP2pTruncate(raw, cols)
|
||||
}
|
||||
bareEditWrite(ctx, stdout, out + '\x1b[?25h')
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof ctx.suspendReplForSubprocess === 'function') {
|
||||
ctx.suspendReplForSubprocess()
|
||||
suspended = true
|
||||
}
|
||||
if (typeof stdin.setRawMode === 'function') stdin.setRawMode(true)
|
||||
if (typeof stdin.resume === 'function') stdin.resume()
|
||||
bareEditWrite(ctx, stdout, '\x1b[?1049h')
|
||||
alt = true
|
||||
await draw()
|
||||
while (loop) {
|
||||
const ev = await bareEditReadKey(reader)
|
||||
if (ev.type === 'eof') break
|
||||
if (ev.type === 'ctrl') {
|
||||
const code = typeof ev.code === 'number' ? ev.code : 0
|
||||
if (ev.code === 'interrupt' || code === 3 || code === 17 || code === 24) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (ev.type === 'key' && ev.ch) {
|
||||
if (ev.ch === 'q' || ev.ch === 'Q') break
|
||||
if (ev.ch === 'r' || ev.ch === 'R') {
|
||||
if (typeof opts.onRefresh === 'function') await opts.onRefresh()
|
||||
await draw()
|
||||
continue
|
||||
}
|
||||
}
|
||||
await draw()
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
if (alt) bareEditWrite(ctx, stdout, '\x1b[?1049l')
|
||||
bareEditWrite(ctx, stdout, '\x1b[?25h\x1b[0m')
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
reader.dispose()
|
||||
try {
|
||||
if (typeof stdin.setRawMode === 'function') stdin.setRawMode(false)
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
if (suspended && typeof ctx.resumeReplAfterSubprocess === 'function') {
|
||||
ctx.resumeReplAfterSubprocess()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user