mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-19 13:35:54 +00:00
Replace terminal.ts in session-card with new buffer-based component that: - Fetches terminal buffer snapshots via JSON API - Polls every second only when content changes (checks lastModified) - Automatically calculates lines needed based on container height - Reuses terminal rendering styles and logic Changes: - Create terminal-renderer.ts with shared rendering logic for both components - Add vibe-terminal-buffer component that works with buffer API - Update session-card to use vibe-terminal-buffer instead of vibe-terminal - Add terminal-line CSS for proper styling - Fix color handling in terminal-manager (-1 means default color) - Add debug logging to help diagnose rendering issues The new approach is more efficient - no cast file parsing, just direct buffer snapshots from the server. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
94 lines
No EOL
2.9 KiB
JavaScript
Executable file
94 lines
No EOL
2.9 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
|
|
// Test script for the new buffer endpoint
|
|
|
|
const BASE_URL = 'http://localhost:3000';
|
|
|
|
async function testBufferEndpoint() {
|
|
try {
|
|
// First, get list of sessions
|
|
const sessionsRes = await fetch(`${BASE_URL}/api/sessions`);
|
|
const sessions = await sessionsRes.json();
|
|
|
|
if (sessions.length === 0) {
|
|
console.log('No sessions available. Create a session first.');
|
|
return;
|
|
}
|
|
|
|
const sessionId = sessions[0].id;
|
|
console.log(`Testing with session: ${sessionId}`);
|
|
|
|
// Test buffer endpoint
|
|
const bufferRes = await fetch(`${BASE_URL}/api/sessions/${sessionId}/buffer?viewportY=0&lines=24`);
|
|
|
|
if (!bufferRes.ok) {
|
|
console.error('Buffer request failed:', bufferRes.status, await bufferRes.text());
|
|
return;
|
|
}
|
|
|
|
const buffer = await bufferRes.arrayBuffer();
|
|
const bytes = new Uint8Array(buffer);
|
|
|
|
console.log(`Received ${bytes.length} bytes`);
|
|
|
|
// Parse header
|
|
if (bytes.length < 16) {
|
|
console.error('Buffer too small for header');
|
|
return;
|
|
}
|
|
|
|
const magic = (bytes[1] << 8) | bytes[0];
|
|
const version = bytes[2];
|
|
const flags = bytes[3];
|
|
const cols = (bytes[5] << 8) | bytes[4];
|
|
const rows = (bytes[7] << 8) | bytes[6];
|
|
const viewportY = (bytes[9] << 8) | bytes[8];
|
|
const cursorX = (bytes[11] << 8) | bytes[10];
|
|
const cursorY = (bytes[13] << 8) | bytes[12];
|
|
|
|
console.log('\nHeader:');
|
|
console.log(` Magic: 0x${magic.toString(16)} (${magic === 0x5654 ? 'Valid' : 'Invalid'})`);
|
|
console.log(` Version: ${version}`);
|
|
console.log(` Flags: ${flags}`);
|
|
console.log(` Terminal: ${cols}x${rows}`);
|
|
console.log(` ViewportY: ${viewportY}`);
|
|
console.log(` Cursor: (${cursorX}, ${cursorY})`);
|
|
|
|
// Sample first few cells
|
|
console.log('\nFirst few cells:');
|
|
let offset = 16;
|
|
for (let i = 0; i < Math.min(10, bytes.length - 16); i++) {
|
|
if (offset >= bytes.length) break;
|
|
|
|
const byte = bytes[offset];
|
|
if (byte === 0xFF) {
|
|
// RLE marker
|
|
const count = bytes[offset + 1];
|
|
console.log(` RLE: ${count} repeated cells`);
|
|
offset += 2;
|
|
} else if (byte === 0xFE) {
|
|
// Empty line marker
|
|
const count = bytes[offset + 1];
|
|
console.log(` Empty lines: ${count}`);
|
|
offset += 2;
|
|
} else if (byte & 0x80) {
|
|
// Extended cell
|
|
console.log(` Extended cell at offset ${offset}`);
|
|
offset += 4; // Skip for now
|
|
} else {
|
|
// Basic cell
|
|
const char = String.fromCharCode(byte);
|
|
const attrs = bytes[offset + 1];
|
|
const fg = bytes[offset + 2];
|
|
const bg = bytes[offset + 3];
|
|
console.log(` Cell: '${char}' fg=${fg} bg=${bg} attrs=${attrs}`);
|
|
offset += 4;
|
|
}
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Test failed:', error);
|
|
}
|
|
}
|
|
|
|
testBufferEndpoint(); |