import test from 'brittle' import { readFile } from 'node:fs/promises' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' import { attachBareOsTuiSdk } from '../../bare-os-booter/lib/bare-os-tui-sdk.js' const __dirname = dirname(fileURLToPath(import.meta.url)) const lib = (name) => join(__dirname, '../lib', name) async function loadBaretopTui() { const parts = await Promise.all([ readFile(lib('edit-ansi.js'), 'utf8'), readFile(lib('baretop-snapshot.js'), 'utf8'), readFile(lib('baretop-ui-helpers.js'), 'utf8'), readFile(lib('baretop-tui.js'), 'utf8') ]) const hook = {} new Function( 'exports', parts.join('\n') + '\nexports.bareTopCreateTuiApp = bareTopCreateTuiApp;\nexports.bareTopTabNames = bareTopTabNames;\nexports.bareTopTuiRunOpts = bareTopTuiRunOpts;\n' )(hook) return hook } function makeStream(isTTY, writes) { return { isTTY: !!isTTY, raw: false, columns: 80, rows: 24, write(s) { writes.push(String(s)) }, setRawMode(v) { this.raw = !!v }, resume() {}, pause() {}, on() {}, removeListener() {} } } function makeCtx() { const writes = [] const ctx = { env: { BARE_TOP_INTERVAL_MS: '1000' }, console: { error() {}, log() {} }, replStdin: makeStream(true, writes), replStdout: makeStream(true, writes), b4a: { from(s) { return Buffer.from(String(s)) } }, vfs: { async writeFile() {} }, suspendReplForSubprocess() {}, resumeReplAfterSubprocess() {} } attachBareOsTuiSdk(ctx) return ctx } function sampleSnap() { return { atMs: 1, metricsLive: { peers: 2, session: { execLineCount: 4, pipelineBytesTotal: 100, execLineWallMsTotal: 10 } }, extra: { processTable: { processes: [ { pid: 1, name: 'bare-os-kernel', state: 'running', startedAtMs: 1 }, { pid: 2, name: 'fish', state: 'sleeping', startedAtMs: 2 } ] }, swarm: { peers: 2 }, replication: { ok: true } }, features: { tuiSdk: true, chat: true }, netSummary: { interfaces: [{ name: 'tun0', rxBytes: 10, txBytes: 4 }] }, initdGraph: { nodes: ['sshd', 'cron'] }, hostOs: { os: 'darwin' }, cpuCoreCount: 4, cpuLine: 'test-cpu', meminfoLine: 'MemTotal: 1024', diskstatsLine: 'sda', fileTexts: { version: 'bare-os 0.1' }, healthScore: 80, healthBreakdown: '' } } test('baretop source prefers ctx.tui.run TEA dashboard', async (t) => { const src = await readFile(lib('baretop-tui.js'), 'utf8') t.ok(src.includes('ctx.tui.run')) t.ok(src.includes("buffer: 'cell'")) t.ok(src.includes('bareTopCreateTuiApp')) }) test('baretop TEA app paints a fixed-height frame and switches tabs', async (t) => { const hook = await loadBaretopTui() const ctx = makeCtx() const app = hook.bareTopCreateTuiApp(ctx, ctx.env) app.width = 80 app.height = 24 app.update({ type: 'baretop.snap', snap: sampleSnap() }) const view = ctx.tui.style.stripAnsi(app.view()) const lines = view.split('\n') t.is(lines.length, 24, 'view is exactly terminal height (no scroll)') t.ok(view.includes('baretop'), 'title') t.ok(view.includes('[overview]'), 'active tab') t.ok(view.includes('Activity') || view.includes('Session'), 'overview body') app.update(ctx.tui.decode('2')[0]) t.is(app._tabName(), 'processes') const proc = ctx.tui.style.stripAnsi(app.view()) t.ok(proc.includes('bare-os-kernel') || proc.includes('PID'), 'process table') const q = app.update(ctx.tui.decode('q')[0]) t.is(typeof q[1], 'function') t.is(q[1]().type, 'quit') }) test('baretop TEA app help overlay and pause', async (t) => { const hook = await loadBaretopTui() const ctx = makeCtx() const app = hook.bareTopCreateTuiApp(ctx, ctx.env) app.update({ type: 'baretop.snap', snap: sampleSnap() }) app.update(ctx.tui.decode('?')[0]) t.ok(app.help) const ov = app.overlay({ width: 80, height: 24 }) t.ok(ov && ctx.tui.style.stripAnsi(ov.text).includes('help')) app.update(ctx.tui.decode('x')[0]) t.absent(app.help) app.update(ctx.tui.decode(' ')[0]) t.ok(app.paused) }) test('kernel baretop bin includes TEA factory after build', async (t) => { const bin = await readFile( join(__dirname, '../../../kernel/bin/baretop'), 'utf8' ) t.ok(bin.includes('bareTopCreateTuiApp')) t.ok(bin.includes('ctx.tui.run')) })