diff --git a/muxplex/frontend/terminal.js b/muxplex/frontend/terminal.js index 4796c14..a4cd60d 100644 --- a/muxplex/frontend/terminal.js +++ b/muxplex/frontend/terminal.js @@ -95,7 +95,7 @@ function _openMuxtermSocket() { if (ws !== _ws) return; // stale guard if (!_term) return; if (e.data instanceof ArrayBuffer) { - // Binary frame: terminal output — write directly to xterm + // Binary frame: terminal output — write directly to terminal var payload = new Uint8Array(e.data); _term.write(_decoder ? _decoder.decode(payload) : payload); } else if (typeof e.data === 'string') { @@ -161,7 +161,7 @@ function initVisualViewport() { // ——— Terminal creation ———————————————————————————————————————————————— /** - * Create (or recreate) the xterm.js Terminal with addons. + * Create (or recreate) the ghostty-web Terminal with addons. * @param {number} [fontSize=14] */ function createTerminal(fontSize) { @@ -412,6 +412,7 @@ function openTerminal(sessionName, remoteId, fontSize) { } else { connectWebSocket(); } + }); // close _ghosttyReady.then(function() { ... }) } // ——— Close terminal ———————————————————————————————————————————————— @@ -467,7 +468,8 @@ function _initAndroidIMEFix(container) { if (!/Android/i.test(navigator.userAgent)) return; setTimeout(function() { - var ta = container.querySelector('.xterm-helper-textarea'); + // ghostty-web may use a different textarea class than xterm.js (.xterm-helper-textarea) + var ta = container.querySelector('textarea'); if (!ta) return; ta.addEventListener('beforeinput', function(e) { diff --git a/muxplex/frontend/tests/test_app.mjs b/muxplex/frontend/tests/test_app.mjs index 5b18ea6..e53b3b3 100644 --- a/muxplex/frontend/tests/test_app.mjs +++ b/muxplex/frontend/tests/test_app.mjs @@ -4110,11 +4110,11 @@ test('tile click handler ignores clicks on tile-options-btn button', () => { // --- index.html: self-hosted vendor libs (no CDN) --- -test('index.html loads xterm.css from local /vendor/ path (not CDN)', () => { +test('index.html loads ghostty-web.js from local /vendor/ path (not CDN)', () => { const html = fs.readFileSync(new URL('../index.html', import.meta.url), 'utf8'); assert.ok( - html.includes('href="/vendor/xterm.css"'), - 'index.html must reference /vendor/xterm.css (not CDN)', + html.includes('ghostty-web.js'), + 'index.html must reference ghostty-web.js (not xterm.js)', ); assert.ok( !html.includes('cdn.jsdelivr.net'), @@ -4122,11 +4122,11 @@ test('index.html loads xterm.css from local /vendor/ path (not CDN)', () => { ); }); -test('index.html loads all 5 xterm JS scripts from local /vendor/ paths (not CDN)', () => { +test('index.html loads ghostty-web and remaining addon scripts from local /vendor/ paths (not CDN)', () => { const html = fs.readFileSync(new URL('../index.html', import.meta.url), 'utf8'); + // ghostty-web replaces xterm.js + xterm-addon-fit.js (fit is built-in) const vendorScripts = [ - '/vendor/xterm.js', - '/vendor/xterm-addon-fit.js', + '/vendor/ghostty-web.js', '/vendor/xterm-addon-web-links.js', '/vendor/xterm-addon-search.js', '/vendor/addon-image.js', diff --git a/muxplex/tests/test_frontend_js.py b/muxplex/tests/test_frontend_js.py index 8b3849f..6ccb5f2 100644 --- a/muxplex/tests/test_frontend_js.py +++ b/muxplex/tests/test_frontend_js.py @@ -2,6 +2,7 @@ import pathlib import re +import subprocess JS_PATH = pathlib.Path(__file__).parent.parent / "frontend" / "app.js" TERMINAL_JS_PATH = pathlib.Path(__file__).parent.parent / "frontend" / "terminal.js" @@ -5004,3 +5005,35 @@ def test_terminal_js_connects_to_muxterm_port_directly() -> None: "terminal.js must reference _muxtermPort — " "WebSocket connects directly to the muxterm port" ) + + +# ── terminal.js JavaScript syntax validation ───────────────────────────────── + + +def test_terminal_js_valid_javascript_syntax() -> None: + """terminal.js must be syntactically valid JavaScript (node -c).""" + result = subprocess.run( + ["node", "-c", str(TERMINAL_JS_PATH)], + capture_output=True, + text=True, + ) + assert result.returncode == 0, ( + f"terminal.js has a JavaScript syntax error:\n{result.stderr}" + ) + + +# ── terminal.js must not have stale xterm.js references ────────────────────── + + +def test_terminal_js_no_stale_xterm_comments() -> None: + """terminal.js comments must not reference xterm.js — use 'terminal' or 'ghostty-web'.""" + # Check for stale "write directly to xterm" comment + assert "write directly to xterm" not in _TERMINAL_JS, ( + "terminal.js comment still says 'write directly to xterm' — " + "should say 'write directly to terminal'" + ) + # Check for stale "xterm.js Terminal" in createTerminal docstring + assert "xterm.js Terminal" not in _TERMINAL_JS, ( + "terminal.js comment still says 'xterm.js Terminal' — " + "should reference ghostty-web" + )