(inputId, resultId, endpoint, verb, rerunFnName)
| 1314 | if (status) status.innerHTML = '<span class="text-red-400">Terminal library failed to load.</span>'; |
| 1315 | return; |
| 1316 | } |
| 1317 | if (!_terminalEnabled()) { |
| 1318 | if (status) status.innerHTML = '<span class="text-amber-300">Web terminal is disabled.</span> Enable it in Config → Web Terminal.'; |
| 1319 | _termTeardown(); |
| 1320 | return; |
| 1321 | } |
| 1322 | if (status) status.textContent = ''; |
| 1323 | |
| 1324 | if (!_term) { |
| 1325 | _term = new Terminal({ cursorBlink: true, fontSize: 13, |
| 1326 | fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace', |
| 1327 | theme: { background: '#0f172a', foreground: '#e2e8f0' } }); |
| 1328 | _termFit = new FitAddon.FitAddon(); |
| 1329 | _term.loadAddon(_termFit); |
| 1330 | _term.open(mount); |
| 1331 | _term.onData(d => { if (_termSocket && _termSocket.connected) _termSocket.emit('terminal_input', { data: d }); }); |
| 1332 | } |
| 1333 | try { _termFit.fit(); } catch (e) { /* mount not sized yet */ } |
| 1334 | |
| 1335 | if (!_termSocket || !_termSocket.connected) { |
| 1336 | _term.reset(); |
| 1337 | _termSocket = io('/terminal', { reconnection: false }); |
| 1338 | _termSocket.on('connect', () => { setTimeout(() => { try { _termFit.fit(); } catch (e) {} _sendTermResize(); _term.focus(); }, 60); }); |
| 1339 | _termSocket.on('terminal_output', d => _term.write(d.data || '')); |
| 1340 | _termSocket.on('terminal_exit', () => _term.write('\r\n\x1b[33m[session ended — press Reconnect for a new shell]\x1b[0m\r\n')); |
| 1341 | _termSocket.on('connect_error', () => _term.write('\r\n\x1b[31m[could not open terminal — is it enabled and are you logged in?]\x1b[0m\r\n')); |
| 1342 | } |
no test coverage detected