Here is a lightweight, zero-dependency Node.js REPL script. It uses Node's
built-in dgram and readline modules, meaning you can drop it straight onto
your Alpine Linux (elli) or Raspberry Pi and run it immediately without
running npm install.
Because your Android APK is built on an event-driven UDP broadcast
architecture, this script will instantly integrate into the mesh. It will
listen for state changes from the phones and allow you to dynamically inject
UI changes (moving windows, changing text, altering colors) back to the
Android devices from your terminal.
1. Create the Script
On your Alpine machine or Raspberry Pi, create a file named hauki_repl.js:
const dgram = require('dgram');
const readline = require('readline');
const PORT = 7777;
const BROADCAST_ADDR = '255.255.255.255';
const MY_ID = 'node-cli-' + Math.floor(Math.random() * 1000);
const sock = dgram.createSocket('udp4');
let windows = {}; // Cache the state of the desktop
/ Initialize UDP Socket
sock.on('listening', () => {
sock.setBroadcast(true);
console.log(`
[HAUKI-REPL] Node ${MY_ID} listening and broadcasting on UDP ${PORT}`);
rl.prompt();
});
/ Handle incoming UDP packets from Android devices
sock.on('message', (msg, rinfo) => {
try {
const payload = JSON.parse(msg);
if (payload.sender === MY_ID) return; // Ignore our own broadcasts
windows[payload.window.id] = payload.window;
// Clear the current prompt line, print the message, and redraw prompt
const cleanText = payload.window.text.replace(/
/g, '\
');
process.stdout.write(`\r\x1b[K[RECV] ${rinfo.address} ->
${payload.window.id} at (${payload.window.x},${payload.window.y}):
"${cleanText}"
`);
rl.prompt();
} catch (e) {
process.stdout.write(`\r\x1b[K[RECV-ERR] Bad payload from
${rinfo.address}
`);
rl.prompt();
}
});
sock.bind(PORT, '0.0.0.0');
/ Initialize REPL Terminal
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: 'hauki> '
});
rl.on('line', (line) => {
const args = line.trim().split(' ');
const cmd = args[0];
if (cmd === 'list') {
const keys = Object.keys(windows);
if (keys.length === 0) console.log("No windows seen yet. Try tapping
one on the Android device.");
else keys.forEach(id => {
let w = windows[id];
console.log(` - ${id} @ (${w.x},${w.y}) [${w.w}x${w.h}]
"${w.title}"`);
});
}
else if (cmd === 'msg' && args.length >= 3) {
sendUpdate(args[1], { text: args.slice(2).join(' ') });
}
else if (cmd === 'move' && args.length === 4) {
sendUpdate(args[1], { x: parseInt(args[2]), y: parseInt(args[3]) });
}
else if (cmd === 'color' && args.length === 3) {
// e.g. color term_1 0xFFFF0000 (Red)
sendUpdate(args[1], { bg: parseInt(args[2]) });
}
else if (cmd === 'spawn' && args.length === 2) {
// Force spawn a new window on all devices
sendUpdate(args[1], {
id: args[1], x: 60, y: 60, w: 200, h: 100,
title: 'REMOTE NODE', text: 'HELLO FROM LINUX',
focused: true, bg: 0xFF222288, fg: 0xFFFFFFFF, border: 0xFF00AAFF
});
}
else if (cmd === 'help') {
console.log(`Commands:
list - Show all known windows in the mesh
msg <id> <text> - Inject text into a window
move <id> <x> <y> - Move window coordinates
color <id> <0xHEX> - Change window background color (ARGB)
spawn <id> - Create a new window on all screens
exit - Close REPL`);
}
else if (cmd === 'exit') {
process.exit(0);
}
else if (line.trim() !== '') {
console.log("Unknown command. Type 'help'.");
}
rl.prompt();
});
function sendUpdate(id, delta) {
// If we haven't seen this window, create a default template so delta
merges cleanly
if (!windows[id]) {
windows[id] = { id: id, x: 50, y: 50, w: 200, h: 150, title:
id.toUpperCase(), text: '', focused: false, bg: 0xFF111111, fg: 0xFF00FF00,
border: 0xFF00AA00 };
}
// Merge the new changes into our cached state
Object.assign(windows[id], delta);
const payload = JSON.stringify({ sender: MY_ID, window: windows[id] });
const buf = Buffer.from(payload);
sock.send(buf, 0, buf.length, PORT, BROADCAST_ADDR, (err) => {
if (err) console.error("Broadcast error:", err);
else console.log(`[SENT] Updated ${id}`);
rl.prompt();
});
}
2. How to Test the Mesh
* Connect your Android phone to the same LAN (or Tailscale network) as the
Linux box.
* Open the Android app.
* Run the script on Linux: node hauki_repl.js
* Tap around and type on the Android screen. You will immediately see the
JSON payloads scrolling in your Linux terminal:
[RECV] 192.168.1.150 -> term_1 at (20,30): "MOCK SYSTEM READY.
> HELLO"
* Control Android from Linux: Type the following into the REPL prompt:
* move term_1 200 200 (Watch the window instantly teleport on the phone)
* color term_1 0xFF0000FF (Changes the terminal background to solid blue)
* msg note_1 SYSTEM OVERRIDE INITIATED (Injects text remotely)
* spawn alerts_1 (Creates a brand new window dynamically on the phone)
Because the C++ engine in the APK uses Object.assign(existing, msg.window),
any property you push from Node.js (like x or bg) will instantly apply on the
next 60fps render cycle, while preserving whatever properties you didn't
explicitly change.