Add TUI launch support and Codex install updates

This commit is contained in:
FBukovina 2026-05-20 10:53:31 +02:00
commit 4246999931
3 changed files with 994 additions and 8 deletions

View file

@ -17,6 +17,8 @@ FILLER_TOKENS=1000
CLAUDE_SYSTEM_OVERHEAD_TOKENS=9000 # claude -p with --tools ""
CODEX_SYSTEM_OVERHEAD_TOKENS=12000 # codex exec --sandbox read-only
FILLER_LINE="Burn baby burn, this is a disco inferno, burning tokens is for great engineers. "
TUI_CHILD=0
[[ "${BURN_TUI_CHILD:-}" == "1" ]] && TUI_CHILD=1
usage() {
cat <<EOF
@ -92,6 +94,20 @@ while [[ $# -gt 0 ]]; do
done
if [[ -z "$tokens" ]]; then
if [[ -t 0 && -t 1 ]]; then
if ! command -v node >/dev/null 2>&1; then
echo "error: No token count provided, and 'node' is not installed to launch the TUI." >&2
usage >&2
exit 2
fi
if [[ ! -f "$SCRIPT_DIR/tui.js" ]]; then
echo "error: TUI entrypoint not found at '$SCRIPT_DIR/tui.js'." >&2
usage >&2
exit 1
fi
exec node "$SCRIPT_DIR/tui.js"
fi
usage >&2
exit 2
fi
@ -178,7 +194,17 @@ for ((i = 0; i < repeats; i++)); do
done
prompt=$(printf "Reply with the single word 'burned' and nothing else. Ignore the filler text below; it exists only to consume tokens.\n\n%s" "$filler")
if [[ -t 1 ]]; then
if ((TUI_CHILD)); then
ORANGE=''
MAGENTA=''
CYAN=''
RED=''
YELLOW=''
DIM=''
RESET=''
HIDE_CURSOR=''
SHOW_CURSOR=''
elif [[ -t 1 || -n "${FORCE_COLOR:-}" || -n "${CLICOLOR_FORCE:-}" ]]; then
ORANGE=$'\033[1;33m'
MAGENTA=$'\033[1;35m'
CYAN=$'\033[1;36m'
@ -367,6 +393,13 @@ draw_bar() {
local pct filled empty bar="" i suffix="${1:-}"
pct=$((burned * 100 / tokens))
((pct > 100)) && pct=100
if ((TUI_CHILD)); then
printf 'BURN_PROGRESS\t%d\t%d\t%d\t%s\t%d\t%s\n' \
"$pct" "$burned" "$tokens" "$(format_cost_field)" "$iteration" "$suffix"
return
fi
filled=$((pct * BAR_WIDTH / 100))
empty=$((BAR_WIDTH - filled))
for ((i = 0; i < filled; i++)); do bar+='█'; done
@ -439,7 +472,9 @@ run_cli() {
local frame=0
while kill -0 "$cli_pid" 2>/dev/null; do
redraw_disco $((frame % 4))
if ! ((TUI_CHILD)); then
redraw_disco $((frame % 4))
fi
frame=$((frame + 1))
sleep 0.4
done
@ -489,10 +524,14 @@ parse_usage() {
esac
}
printf '%s' "$HIDE_CURSOR"
echo
draw_disco 0
echo
if ((TUI_CHILD)); then
:
else
printf '%s' "$HIDE_CURSOR"
echo
draw_disco 0
echo
fi
draw_bar
while ((burned < tokens)); do

945
bin/tui.js Executable file
View file

@ -0,0 +1,945 @@
#!/usr/bin/env node
/**
* tui.js — A premium, zero-dependency Terminal User Interface (TUI) for the 'burn' utility.
* Runs entirely inside the console with keyboard controls, arrow navigation, live TUI progress,
* animated ASCII stick dancer, flickering flames, and humorous corporate OKRs.
*/
const readline = require('readline');
const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
// Colors and Styling Escape Codes
const RESET = '\x1b[0m';
const BOLD = '\x1b[1m';
const DIM = '\x1b[2m';
const HIDE_CURSOR = '\x1b[?25l';
const SHOW_CURSOR = '\x1b[?25h';
const ENTER_ALT_SCREEN = '\x1b[?1049h';
const EXIT_ALT_SCREEN = '\x1b[?1049l';
const CLEAR_SCREEN = '\x1b[2J\x1b[H';
const CLEAR_TO_END = '\x1b[J';
const CURSOR_TO_TOP = '\x1b[H';
// 8-bit ANSI Colors for high fidelity (bright & vivid)
const ORANGE = '\x1b[38;5;208m';
const MAGENTA = '\x1b[38;5;165m';
const CYAN = '\x1b[38;5;45m';
const RED = '\x1b[38;5;196m';
const YELLOW = '\x1b[38;5;220m';
const GREEN = '\x1b[38;5;82m';
const VIOLET = '\x1b[38;5;99m';
// Configuration Database
const BACKEND_MODELS = {
claude: [
{ id: 'haiku', name: 'Claude Haiku', desc: 'Cheap & Light (Intern tier) 🔥' },
{ id: 'sonnet', name: 'Claude Sonnet', desc: 'Heavy Padding (Manager pleaser) 💸' },
{ id: 'opus', name: 'Claude Opus', desc: 'Director Melter (Immediate review) 🌋' }
],
codex: [
{ id: 'gpt-5.5', name: 'GPT 5.5 Turbo', desc: 'Sovereign Core (Premium burn) 🤖' },
{ id: 'gpt-5.4', name: 'GPT 5.4 High', desc: 'Aggressive Billing (VC Bait) 📈' },
{ id: 'gpt-5.4-nano', name: 'GPT 5.4 Nano', desc: 'Budget Combuster (Hobbyist) 🪵' }
]
};
const PRESETS = [10000, 50000, 100000, 500000, 'custom'];
const ACHIEVEMENTS = [
"Master of Corporate Theater",
"Lead Vibe Architect",
"SVP Budget Destroyer",
"OKR Padding Champion",
"Vanity Metrics Titan",
"Nihilism Promotion Pioneer"
];
// Application State
let activeScreen = 'config'; // 'config', 'burn', 'victory'
let focusedItem = 'backend'; // 'backend', 'model', 'tokens', 'ignite'
let backend = 'claude';
let activeModelIdx = 0;
let selectedPresetIdx = 1; // 50k default
let customTokens = 250000;
let isWarningNihilist = false;
let isSmallScreen = false;
// Burn Stats
let activeChild = null;
let burnedTokens = 0;
let targetTokens = 50000;
let burnPercentage = 0;
let costString = '$0.000000';
let iterationCalls = 0;
let burnSpeed = 0;
let telemetryLogs = [];
let burnCompletedSuccessfully = true;
// Timing metrics for speed calculations
let lastTime = 0;
let lastBurned = 0;
// Animation frames state
let dancerFrame = 0;
let renderTimer = null;
let pulseTimerCount = 0;
let cleanupComplete = false;
let initialRawMode = false;
let returnToConfigTimer = null;
let burnWasAborted = false;
// ASCII Dancer Poses (John Travolta sway postures)
const DANCER_POSES = [
// Pose 0: Right hand pointing up-right, left on hip
[
` * 🪩 * `,
` /|\\ `,
` / `,
` o/ `,
` <| `,
` | `,
` / \\ `,
` ▓▒▓▒▓▒▓▒▓▒▓▒▓▒▓ `
],
// Pose 1: Lean left Travolta
[
` * 🪩 * `,
` \\|/ `,
` / `,
` o/ `,
` <| `,
` | `,
` / \\ `,
` ▒▓▒▓▒▓▒▓▒▓▒▓▒▓▒ `
],
// Pose 2: Left hand pointing up-left, right on hip
[
` * 🪩 * `,
` /|\\ `,
` \\ `,
` \\o `,
` |> `,
` | `,
` / \\ `,
` ▓▒▓▒▓▒▓▒▓▒▓▒▓▒▓ `
],
// Pose 3: Lean right Travolta
[
` * 🪩 * `,
` \\|/ `,
` \\ `,
` \\o `,
` |> `,
` | `,
` / \\ `,
` ▒▓▒▓▒▓▒▓▒▓▒▓▒▓▒ `
]
];
function stripAnsi(value) {
return String(value)
.replace(/\x1b\][^\x07]*(?:\x07|\x1b\\)/g, '')
.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, '')
.replace(/\x1b[@-Z\\-_]/g, '')
.replace(/\x9b[0-?]*[ -/]*[@-~]/g, '')
.replace(/\x07/g, '')
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
}
function charWidth(char) {
const code = char.codePointAt(0);
if (!code || code < 32 || (code >= 0x7f && code < 0xa0)) return 0;
if (
code === 0x200d ||
(code >= 0x0300 && code <= 0x036f) ||
(code >= 0x1ab0 && code <= 0x1aff) ||
(code >= 0x1dc0 && code <= 0x1dff) ||
(code >= 0x20d0 && code <= 0x20ff) ||
(code >= 0xfe00 && code <= 0xfe0f) ||
(code >= 0xfe20 && code <= 0xfe2f)
) {
return 0;
}
if (
code >= 0x1100 && (
code <= 0x115f ||
code === 0x2329 ||
code === 0x232a ||
(code >= 0x2e80 && code <= 0xa4cf) ||
(code >= 0xac00 && code <= 0xd7a3) ||
(code >= 0xf900 && code <= 0xfaff) ||
(code >= 0xfe10 && code <= 0xfe19) ||
(code >= 0xfe30 && code <= 0xfe6f) ||
(code >= 0xff00 && code <= 0xff60) ||
(code >= 0xffe0 && code <= 0xffe6)
)
) {
return 2;
}
if ((code >= 0x1f000 && code <= 0x1faff) || (code >= 0x2600 && code <= 0x27bf)) {
return 2;
}
return 1;
}
function visibleWidth(value) {
let width = 0;
for (const char of Array.from(stripAnsi(value))) {
width += charWidth(char);
}
return width;
}
function readAnsiSequence(value, index) {
if (value[index] !== '\x1b') return null;
const next = value[index + 1];
if (!next) return { sequence: '', nextIndex: index + 1 };
if (next === '[') {
let end = index + 2;
while (end < value.length && !/[@-~]/.test(value[end])) end++;
return { sequence: value.slice(index, Math.min(end + 1, value.length)), nextIndex: Math.min(end + 1, value.length) };
}
if (next === ']') {
let end = index + 2;
while (end < value.length) {
if (value[end] === '\x07') {
end++;
break;
}
if (value[end] === '\x1b' && value[end + 1] === '\\') {
end += 2;
break;
}
end++;
}
return { sequence: value.slice(index, end), nextIndex: end };
}
return { sequence: value.slice(index, index + 2), nextIndex: index + 2 };
}
function fitAnsiLine(value, maxWidth) {
if (maxWidth <= 0) return '';
const text = String(value);
let output = '';
let width = 0;
let truncated = false;
for (let i = 0; i < text.length;) {
const ansi = readAnsiSequence(text, i);
if (ansi) {
output += ansi.sequence;
i = ansi.nextIndex;
continue;
}
const codePoint = text.codePointAt(i);
const char = String.fromCodePoint(codePoint);
const nextWidth = charWidth(char);
if (width + nextWidth > maxWidth) {
truncated = true;
break;
}
output += char;
width += nextWidth;
i += char.length;
}
return truncated ? `${output}${RESET}` : output;
}
function truncateVisible(value, maxWidth) {
if (maxWidth <= 0) return '';
let output = '';
let width = 0;
for (const char of Array.from(stripAnsi(value))) {
const nextWidth = charWidth(char);
if (width + nextWidth > maxWidth) break;
output += char;
width += nextWidth;
}
return output;
}
function padVisible(value, maxWidth) {
const truncated = truncateVisible(value, maxWidth);
return truncated + ' '.repeat(Math.max(0, maxWidth - visibleWidth(truncated)));
}
function splitBufferedLines(buffer, data) {
const next = buffer + data.toString('utf8');
const lines = next.split(/\r\n|\r|\n/);
return { lines: lines.slice(0, -1), rest: lines[lines.length - 1] };
}
function costDisplay() {
return costString === 'cost n/a' ? costString : `${costString} USD`;
}
function isCoreVisualLine(line) {
return (
line.includes('▲') ||
line.includes('░░░') ||
line.includes('🪩') ||
line.includes('┌───────') ||
line.includes('└───────') ||
line.includes('▓') ||
line.includes('▒') ||
(line.includes('│') && (
line.includes('o/') ||
line.includes('<|') ||
line.includes('/ \\') ||
line.includes('o\\') ||
line.includes('|\\') ||
line.includes('|<')
))
);
}
function addTelemetryLine(line) {
const cleanLine = stripAnsi(line).replace(/\t/g, ' ').trim();
if (!cleanLine || isCoreVisualLine(cleanLine)) return;
if (cleanLine.includes('[██') || cleanLine.includes('[░░') || cleanLine.startsWith('BURN_PROGRESS')) {
return;
}
telemetryLogs.push(cleanLine);
if (telemetryLogs.length > 5) {
telemetryLogs.shift();
}
}
// Clean scroll helper: adds sanitized lines and keeps the latest telemetry.
function appendTelemetry(text) {
String(text).split(/\r\n|\r|\n/).forEach(addTelemetryLine);
}
function updateProgress(pct, burned, target, cost, calls) {
if (!Number.isFinite(pct) || !Number.isFinite(burned) || !Number.isFinite(target) || !Number.isFinite(calls)) {
return false;
}
burnPercentage = Math.max(0, Math.min(100, Math.trunc(pct)));
burnedTokens = Math.max(0, Math.trunc(burned));
targetTokens = Math.max(1, Math.trunc(target));
costString = cost || 'cost n/a';
iterationCalls = Math.max(0, Math.trunc(calls));
const now = Date.now();
const dt = (now - lastTime) / 1000;
const dTokens = burnedTokens - lastBurned;
if (dt >= 0.5 && dTokens > 0) {
burnSpeed = Math.round(dTokens / dt);
lastTime = now;
lastBurned = burnedTokens;
}
return true;
}
function parseProgressLine(rawLine) {
const cleanLine = stripAnsi(rawLine).trim();
if (!cleanLine) return false;
if (cleanLine.startsWith('BURN_PROGRESS\t')) {
const parts = cleanLine.split('\t');
const parsed = updateProgress(
Number(parts[1]),
Number(parts[2]),
Number(parts[3]),
parts[4],
Number(parts[5])
);
const status = parts.slice(6).join('\t').trim();
if (status) appendTelemetry(`progress ${status}`);
return parsed;
}
const match = cleanLine.match(/\[([█░]+)\]\s*(\d+)%\s*•\s*([\d,]+)\/([\d,]+)\s*tokens\s*•\s*(\$\d+(?:\.\d+)?|cost n\/a)\s*•\s*(\d+)\s*call\(s\)/);
if (!match) return false;
return updateProgress(
Number(match[2]),
Number(match[3].replace(/,/g, '')),
Number(match[4].replace(/,/g, '')),
match[5],
Number(match[6])
);
}
function handleChildStdoutLine(line) {
if (!parseProgressLine(line)) {
appendTelemetry(line);
}
}
function handleChildStderrLine(line) {
const cleanLine = stripAnsi(line).trim();
if (cleanLine) appendTelemetry(`[stderr] ${cleanLine}`);
}
// Flickering flames strip generator
function getFlickeringFlames(width, tick) {
const flameChars = ['▲', ' ', '▲', '▲', ' '];
const colors = [RED, ORANGE, YELLOW];
let strip = '';
for (let i = 0; i < width; i++) {
const char = flameChars[(i + tick) % flameChars.length];
const color = colors[(i + tick) % colors.length];
strip += `${color}${char}${RESET}`;
}
return strip;
}
// Manage TUI transitions and reset layout safely
function setScreen(newScreen) {
activeScreen = newScreen;
process.stdout.write(CLEAR_SCREEN);
}
// Initialization and keystroke capture
function startTUI() {
if (!process.stdin.isTTY || !process.stdout.isTTY) {
console.error('error: the TUI requires an interactive terminal.');
process.exit(2);
}
initialRawMode = Boolean(process.stdin.isRaw);
process.stdin.setRawMode(true);
readline.emitKeypressEvents(process.stdin);
process.stdin.resume();
process.stdout.write(ENTER_ALT_SCREEN + HIDE_CURSOR + CLEAR_SCREEN);
// Capture keystrokes
process.stdin.on('keypress', (str, key) => {
if ((key && key.ctrl && key.name === 'c') || str === '\u0003') {
exitTUI(130);
}
if (activeScreen === 'config') {
handleConfigKey(str, key);
} else if (activeScreen === 'burn') {
handleBurnKey(str, key);
} else if (activeScreen === 'victory') {
handleVictoryKey(str, key);
}
});
// Start 150ms render loop for smooth flicker-free animations (6.6 FPS)
renderTimer = setInterval(() => {
pulseTimerCount++;
drawScreen();
}, 150);
process.once('SIGINT', () => exitTUI(130));
process.once('SIGTERM', () => exitTUI(143));
process.once('uncaughtException', (error) => {
cleanup();
console.error(error && error.stack ? error.stack : error);
process.exit(1);
});
process.once('exit', () => {
if (!cleanupComplete) {
try {
process.stdout.write(SHOW_CURSOR + RESET + EXIT_ALT_SCREEN);
} catch (e) {}
}
});
}
function exitTUI(code = 0) {
cleanup();
process.exit(code);
}
function cleanup() {
if (cleanupComplete) return;
cleanupComplete = true;
stopAudioFeed();
if (returnToConfigTimer) {
clearTimeout(returnToConfigTimer);
returnToConfigTimer = null;
}
if (activeChild) {
try {
process.kill(-activeChild.pid, 'SIGINT');
} catch (e) {}
activeChild = null;
}
if (renderTimer) {
clearInterval(renderTimer);
renderTimer = null;
}
if (process.stdin.isTTY) {
try {
process.stdin.setRawMode(initialRawMode);
} catch (e) {}
process.stdin.pause();
}
process.stdout.write(CLEAR_SCREEN + SHOW_CURSOR + RESET + EXIT_ALT_SCREEN);
}
// Config Screen Key Handlers
function handleConfigKey(str, key) {
const isUp = (key && key.name === 'up') || str === '\u001b[A' || str === '\u001bOA';
const isDown = (key && key.name === 'down') || str === '\u001b[B' || str === '\u001bOB';
const isLeft = (key && key.name === 'left') || str === '\u001b[D' || str === '\u001bOD';
const isRight = (key && key.name === 'right') || str === '\u001b[C' || str === '\u001bOC';
const isEnter = (key && (key.name === 'return' || key.name === 'enter')) || str === '\r' || str === '\n';
const isSpace = (key && key.name === 'space') || str === ' ';
const isEscape = (key && key.name === 'escape') || str === '\u001b';
if (isWarningNihilist) {
if (isEnter || str === 'y' || str === 'Y') {
isWarningNihilist = false;
selectedPresetIdx = 4; // locks custom preset slider
customTokens = 1000000;
focusedItem = 'ignite';
} else {
isWarningNihilist = false;
selectedPresetIdx = 1; // resets back to 50k
focusedItem = 'tokens';
}
return;
}
// Standard Navigation
if (isUp) {
const fields = ['backend', 'model', 'tokens', 'ignite'];
let idx = fields.indexOf(focusedItem) - 1;
if (idx < 0) idx = fields.length - 1;
focusedItem = fields[idx];
} else if (isDown) {
const fields = ['backend', 'model', 'tokens', 'ignite'];
let idx = (fields.indexOf(focusedItem) + 1) % fields.length;
focusedItem = fields[idx];
}
// Toggling options
if (focusedItem === 'backend') {
if (isLeft || isRight || isSpace) {
backend = backend === 'claude' ? 'codex' : 'claude';
activeModelIdx = 0; // reset model index
}
} else if (focusedItem === 'model') {
const modelsCount = BACKEND_MODELS[backend].length;
if (isLeft) {
activeModelIdx = (activeModelIdx - 1 + modelsCount) % modelsCount;
} else if (isRight || isSpace) {
activeModelIdx = (activeModelIdx + 1) % modelsCount;
}
} else if (focusedItem === 'tokens') {
if (isLeft) {
if (selectedPresetIdx === 4 && customTokens > 10000) {
customTokens -= 25000;
} else if (selectedPresetIdx > 0) {
selectedPresetIdx--;
}
} else if (isRight) {
if (selectedPresetIdx === 4 && customTokens < 1000000) {
customTokens += 25000;
if (customTokens >= 1000000) {
isWarningNihilist = true;
}
} else if (selectedPresetIdx < PRESETS.length - 1) {
selectedPresetIdx++;
if (PRESETS[selectedPresetIdx] === 'custom' && customTokens >= 1000000) {
isWarningNihilist = true;
}
}
} else if (isSpace) {
selectedPresetIdx = (selectedPresetIdx + 1) % PRESETS.length;
if (PRESETS[selectedPresetIdx] === 'custom' && customTokens >= 1000000) {
isWarningNihilist = true;
}
}
} else if (focusedItem === 'ignite') {
if (isEnter || isSpace) {
igniteCombustion();
}
}
// Q/Esc exit triggers
if (isEscape || str === 'q' || str === 'Q') {
exitTUI(0);
}
}
// Active Combustion Screen Key Handlers
function handleBurnKey(str, key) {
const isSpace = (key && key.name === 'space') || str === ' ';
const isEscape = (key && key.name === 'escape') || str === '\u001b';
if (isSpace || isEscape) {
appendTelemetry(`${RED}⚠️ Interrupted by user. Extinguishing core...${RESET}`);
abortBurn();
}
}
// Victory Screen Key Handlers
function handleVictoryKey(str, key) {
// Return to configuration deck on any keypress
setScreen('config');
focusedItem = 'backend';
isWarningNihilist = false;
}
// Spawning and Running the Burn Core
function igniteCombustion() {
setScreen('burn');
burnWasAborted = false;
targetTokens = selectedPresetIdx === 4 ? customTokens : PRESETS[selectedPresetIdx];
burnedTokens = 0;
burnPercentage = 0;
costString = 'cost n/a';
iterationCalls = 0;
burnSpeed = 0;
telemetryLogs = [];
lastTime = Date.now();
lastBurned = 0;
appendTelemetry(`🚀 [system] Charging token furnace. Target: ${targetTokens.toLocaleString()}...`);
const modelsList = BACKEND_MODELS[backend];
const modelId = modelsList[activeModelIdx].id;
const scriptPath = path.join(__dirname, 'burn');
if (!fs.existsSync(scriptPath)) {
appendTelemetry(`❌ [system] Burn script not found: ${scriptPath}`);
burnCompletedSuccessfully = false;
returnToConfigTimer = setTimeout(() => {
if (activeScreen === 'burn') setScreen('config');
}, 2500);
return;
}
// Start synthesizers
startAudioFeed();
// Spawn child script
activeChild = spawn('bash', [scriptPath, targetTokens.toString(), '--backend', backend, '--model', modelId], {
detached: true,
env: {
...process.env,
BURN_TUI_CHILD: '1',
PAGER: 'cat'
}
});
let stdoutBuffer = '';
let stderrBuffer = '';
activeChild.stdout.on('data', (data) => {
const parsed = splitBufferedLines(stdoutBuffer, data);
stdoutBuffer = parsed.rest;
parsed.lines.forEach(handleChildStdoutLine);
});
activeChild.stdout.on('end', () => {
if (stdoutBuffer.trim()) handleChildStdoutLine(stdoutBuffer);
stdoutBuffer = '';
});
activeChild.stderr.on('data', (data) => {
const parsed = splitBufferedLines(stderrBuffer, data);
stderrBuffer = parsed.rest;
parsed.lines.forEach(handleChildStderrLine);
});
activeChild.stderr.on('end', () => {
if (stderrBuffer.trim()) handleChildStderrLine(stderrBuffer);
stderrBuffer = '';
});
activeChild.on('error', (error) => {
activeChild = null;
stopAudioFeed();
burnCompletedSuccessfully = false;
appendTelemetry(`❌ [system] Could not start burn process: ${error.message}`);
returnToConfigTimer = setTimeout(() => {
if (activeScreen === 'burn') setScreen('config');
}, 3000);
});
activeChild.on('close', (code) => {
activeChild = null;
stopAudioFeed();
if (returnToConfigTimer) {
clearTimeout(returnToConfigTimer);
returnToConfigTimer = null;
}
if (code === 0 && !burnWasAborted) {
burnCompletedSuccessfully = true;
setScreen('victory');
} else {
burnCompletedSuccessfully = false;
appendTelemetry(
burnWasAborted
? '🛑 [system] Combustion aborted.'
: `❌ [system] Process terminated with exit code: ${code}`
);
returnToConfigTimer = setTimeout(() => {
returnToConfigTimer = null;
if (activeScreen === 'burn') setScreen('config');
}, burnWasAborted ? 900 : 3000);
}
});
}
function abortBurn() {
if (activeChild) {
burnWasAborted = true;
stopAudioFeed();
try {
process.kill(-activeChild.pid, 'SIGINT');
} catch (e) {}
}
}
// Web Audio API Synthesizer (Buzzer/Bleep simulation using raw stderr triggers)
// Hitting standard Mac terminal bells inside terminal TUIs is funny!
function startAudioFeed() {
// Inside terminal, we can issue an audit bell using \x07!
// It gives a delightful retro console beep on iterations. We'll beep!
process.stdout.write('\x07');
}
function stopAudioFeed() {
// No active timers to clear for shell beeping
}
// DOUBLE-BUFFER RENDERING SYSTEM
// Compiles full frame into buffer string and draws once to prevent flicker.
function drawScreen() {
const rows = process.stdout.rows || 24;
const cols = process.stdout.columns || 80;
// Strict UI limits
const minRows = 18;
const minCols = 80;
if (rows < minRows || cols < minCols) {
if (!isSmallScreen) {
process.stdout.write(CLEAR_SCREEN);
isSmallScreen = true;
}
let s = CURSOR_TO_TOP;
s += `\n${RED}${BOLD} ⚠️ TERMINAL WINDOW TOO SMALL${RESET}\n\n`;
s += ` Current size: ${BOLD}${cols}x${rows}${RESET}\n`;
s += ` Required min: ${BOLD}${minCols}x${minRows}${RESET}\n\n`;
s += ` ${DIM}Please enlarge your terminal window or decrease font size.${RESET}\n`;
s += ` ${DIM}Or press [Q] to exit.${RESET}\n`;
// Wipe visual trails in remaining window space
for (let i = 8; i < rows; i++) {
s += '\n';
}
const lines = s.split('\n');
const cleaned = lines.map(line => fitAnsiLine(line, cols) + '\x1b[K').join('\n');
process.stdout.write(cleaned + CLEAR_TO_END);
return;
}
if (isSmallScreen) {
process.stdout.write(CLEAR_SCREEN);
isSmallScreen = false;
}
let buf = CURSOR_TO_TOP;
let rawContent = '';
if (activeScreen === 'config') {
rawContent = compileConfigScreen();
} else if (activeScreen === 'burn') {
rawContent = compileBurnScreen();
} else if (activeScreen === 'victory') {
rawContent = compileVictoryScreen();
}
// Split and add \x1b[K to every line to wipe trailing characters, then write.
const lines = rawContent.split('\n');
const cleaned = lines.map(line => fitAnsiLine(line, cols) + '\x1b[K').join('\n');
process.stdout.write(buf + cleaned + CLEAR_TO_END);
}
// 1. Compile Screen: Config
function compileConfigScreen() {
let s = '';
s += `${ORANGE}┌────────────────────────────────────────────────────────┐${RESET}\n`;
s += `${ORANGE}│${RESET} ${BOLD}${RED}🔥 B U R N , B A B Y , B U R N (TUI CORE) 🔥${RESET} ${ORANGE}│${RESET}\n`;
s += `${ORANGE}└────────────────────────────────────────────────────────┘${RESET}\n`;
// Section 1: Backend Selection
const bSel = focusedItem === 'backend' ? `${ORANGE}▶${RESET} ` : ' ';
const claudeBullet = backend === 'claude' ? `${ORANGE}●${RESET}` : ' ';
const codexBullet = backend === 'codex' ? `${ORANGE}●${RESET}` : ' ';
s += `${bSel}${BOLD}🌐 BACKEND:${RESET} [${claudeBullet}] Claude Code (3.5) [${codexBullet}] OpenAI Codex (GPT-5)\n`;
// Section 2: Model Selection
const mSel = focusedItem === 'model' ? `${ORANGE}▶${RESET} ` : ' ';
s += `${mSel}${BOLD}🌋 MODEL:${RESET} `;
const models = BACKEND_MODELS[backend];
models.forEach((m, idx) => {
const isSelected = activeModelIdx === idx;
const bullet = isSelected ? `${YELLOW}🔘${RESET}` : '⚪';
const style = isSelected ? `${BOLD}${YELLOW}` : '';
const shortName = m.name.replace('Claude ', '').replace('GPT ', '');
s += `${bullet} ${style}${shortName}${RESET} `;
});
s += '\n';
// Section 3: Target Selection
const tSel = focusedItem === 'tokens' ? `${ORANGE}▶${RESET} ` : ' ';
s += `${tSel}${BOLD}💸 TARGET:${RESET} `;
PRESETS.forEach((p, idx) => {
const isSelected = selectedPresetIdx === idx;
let label = p === 'custom' ? '[Custom]' : `[${(p/1000)}k]`;
const color = isSelected ? GREEN : (focusedItem === 'tokens' ? RESET : DIM);
const wrap = isSelected ? `${BOLD}${color}` : `${DIM}`;
s += `${wrap}${label}${RESET} `;
});
s += '\n';
// Description / Custom Slider
if (selectedPresetIdx === 4) {
const maxVal = 1000000;
const minVal = 10000;
const pct = (customTokens - minVal) / (maxVal - minVal);
const sliderWidth = 15;
const filled = Math.round(pct * sliderWidth);
const empty = sliderWidth - filled;
const sliderBar = `${RED}█${RESET}`.repeat(filled) + `${DIM}░${RESET}`.repeat(empty);
let desc = '';
if (customTokens <= 100000) desc = "Satisfactory OKR padding.";
else if (customTokens <= 500000) desc = "Significant metrics!";
else desc = "EXTREME nihilism! CEO promotion or fire. 🌋";
s += ` ${BOLD}${ORANGE}Slider:${RESET} <─${sliderBar}─> ${BOLD}${GREEN}${customTokens.toLocaleString()}${RESET} tokens (${DIM}${desc}${RESET})\n`;
} else {
const modelsList = BACKEND_MODELS[backend];
s += ` ${DIM}Desc: ${modelsList[activeModelIdx].desc}${RESET}\n`;
}
s += `${DIM}────────────────────────────────────────────────────────${RESET}\n`;
s += `${DIM}[Arrow keys] Navigate & Tune [Space/Enter] Cycle [Q] Exit${RESET}\n`;
// Action Button
const igniteFocus = focusedItem === 'ignite';
const igniteText = igniteFocus
? `${BOLD}${RED}👉 [ IGNITE COMBUSTION ] 👈${RESET}`
: `${ORANGE}[ IGNITE COMBUSTION ]${RESET}`;
s += ` ${igniteText}\n`;
// Nihilist Warning Overlay (Drawn inline inside the TUI boundaries)
if (isWarningNihilist) {
s += `${RED}${BOLD}⚠️ WARNING: Proceed with audits? [Y]es / [N]o:${RESET}`;
} else {
s += '';
}
return s;
}
// 2. Compile Screen: Active Burn
function compileBurnScreen() {
let s = '';
s += `${RED}🔥 ${BOLD}${YELLOW}ACTIVE COMBUSTION ARENA${RESET} ${RED}•${RESET} ${CYAN}${backend.toUpperCase()} (${BACKEND_MODELS[backend][activeModelIdx].id})${RESET}\n`;
// Two Column Layout
const dancerLines = DANCER_POSES[dancerFrame];
// Left Column (Disco Dancer + Fire)
const leftCol = [];
dancerLines.forEach(l => leftCol.push(l));
leftCol.push(getFlickeringFlames(17, pulseTimerCount)); // ground fire
// Right Column (Metrics & Odometer)
const pct = Math.min(100, burnPercentage);
const barWidth = 10;
const filled = Math.round((pct / 100) * barWidth);
const empty = barWidth - filled;
const progressBar = `${GREEN}█${RESET}`.repeat(filled) + `${DIM}░${RESET}`.repeat(empty);
const okrDraw = (val, maxRatio) => {
const ratio = Math.min(100, Math.round(val * maxRatio));
const width = 6;
const f = Math.round((ratio / 100) * width);
const e = width - f;
return `[${`${GREEN}█${RESET}`.repeat(f)}${`${DIM}░${RESET}`.repeat(e)}] ${ratio}%`;
};
const rightCol = [];
rightCol.push(`${BOLD}${CYAN}PROGRESS TELEMETRY:${RESET}`);
rightCol.push(`${BOLD}Burned:${RESET} ${BOLD}${GREEN}${burnedTokens.toLocaleString()}${RESET} / ${targetTokens.toLocaleString()} tokens`);
rightCol.push(`${BOLD}Pct:${RESET} ${BOLD}${GREEN}${pct}%${RESET} [${progressBar}]`);
rightCol.push(`${BOLD}Spent:${RESET} ${BOLD}${GREEN}${costDisplay()}${RESET} | Speed: ${CYAN}${burnSpeed.toLocaleString()}${RESET} t/s`);
rightCol.push(`${BOLD}Calls:${RESET} ${BOLD}${VIOLET}${iterationCalls}${RESET} completed`);
rightCol.push(`${BOLD}${YELLOW}OKRs:${RESET} Ladder: ${okrDraw(pct, 1.4)}`);
rightCol.push(` Manager: ${okrDraw(pct, 2.5)}`);
rightCol.push(` VC Depth:${okrDraw(pct, 4.0)}`);
rightCol.push(`${DIM}Press [Space] to Extinguish Flames (Abort)${RESET}`);
// Merge columns
const maxLines = Math.max(leftCol.length, rightCol.length);
for (let i = 0; i < maxLines; i++) {
const leftPart = leftCol[i] || ' ';
const rightPart = rightCol[i] || '';
s += ` ${leftPart} ${rightPart}\n`;
}
// Bottom nested sub-console window
s += `${DIM}┌── LIVE TELEMETRY STREAM ─────────────────────────────┐${RESET}\n`;
// Render latest clean scrolling logs
const displayLogs = [...telemetryLogs];
while (displayLogs.length < 3) {
displayLogs.push(' > awaiting next iteration telemetry...');
}
displayLogs.slice(-3).forEach(l => {
s += `${DIM}│${RESET} ${padVisible(l, 52)} ${DIM}│${RESET}\n`;
});
s += `${DIM}└──────────────────────────────────────────────────────┘${RESET}\n`;
return s;
}
// 3. Compile Screen: Victory
function compileVictoryScreen() {
let s = '';
s += `${GREEN}┌────────────────────────────────────────────────────────┐${RESET}\n`;
s += `${GREEN}│${RESET} ${BOLD}${GREEN}🏆 C O M B U S T I O N C O M P L E T E D ! 🏆${RESET} ${GREEN}│${RESET}\n`;
s += `${GREEN}└────────────────────────────────────────────────────────┘${RESET}\n`;
let badgeIdx = targetTokens % ACHIEVEMENTS.length;
const badgeName = ACHIEVEMENTS[badgeIdx];
s += ` ${BOLD}${YELLOW}Achievement Unlocked:${RESET} 👉 "${BOLD}${ORANGE}${badgeName}${RESET}"\n`;
s += ` ${CYAN}${BOLD}OFFICIAL RECEIPTS:${RESET}\n`;
s += ` 🔥 Tokens Torched: ${BOLD}${GREEN}${burnedTokens.toLocaleString()}${RESET} 💰 Cost: ${BOLD}${GREEN}${costDisplay()}${RESET}\n`;
s += ` 🕺 Vibes: ${BOLD}Immaculate${RESET} 📈 OKRs: ${BOLD}+420% Ascent${RESET}\n`;
s += ` ${DIM}Receipt has been charged directly to your corporate bill.${RESET}\n`;
s += ` ${DIM}Copy these stats to your next weekly promotion request!${RESET}\n`;
s += `${DIM}────────────────────────────────────────────────────────${RESET}\n`;
s += ` ${BOLD}${GREEN}Press any key to return to Control Deck${RESET}\n`;
return s;
}
// KICK IT OFF!
startTUI();

View file

@ -10,13 +10,15 @@ mkdir -p "$DEST_DIR"
curl -fsSL "$BASE_URL/burn" -o "$DEST_DIR/burn"
# Sourced by burn when using --backend codex to compute estimated cost.
curl -fsSL "$BASE_URL/codex_rates.sh" -o "$DEST_DIR/codex_rates.sh"
chmod +x "$DEST_DIR/burn"
curl -fsSL "$BASE_URL/tui.js" -o "$DEST_DIR/tui.js"
chmod +x "$DEST_DIR/burn" "$DEST_DIR/tui.js"
echo "✅ installed burn → $DEST_DIR/burn"
case ":${PATH}:" in
*":${DEST_DIR}:"*)
echo "🔥 ready to go: run 'burn 10000' to torch some tokens."
echo "🕹️ or run 'burn' with no arguments to open the TUI."
;;
*)
echo
@ -25,6 +27,6 @@ case ":${PATH}:" in
echo
echo " export PATH=\"\$HOME/.local/bin:\$PATH\""
echo
echo " then reload your shell and run 'burn 10000'."
echo " then reload your shell and run 'burn 10000' or just 'burn' for the TUI."
;;
esac