document.addEventListener('alpine:init', () => { const el = document.getElementById('hosts-data'); const hostOptions = el ? JSON.parse(el.textContent) : []; const selEl = document.getElementById('selected-host'); const selectedHostId = selEl ? JSON.parse(selEl.textContent) : ''; function processCommand(cmd, tabName) { const lines = []; const clean = cmd.toLowerCase().trim(); if (!clean) return lines; if (clean === 'clear') return []; const commands = { help: [ { text: 'HostKeeper Mock SSH Interactive Command Parser:', type: 'success' }, { text: ' help - Display this support manifest list', type: 'output' }, { text: ' ls - List contents of the current working directory', type: 'output' }, { text: ' docker ps - List simulated running Docker containers on cluster', type: 'output' }, { text: ' uname -a - Show operating system and machine kernel data', type: 'output' }, { text: ' ping 8.8.8.8 - Probe network gateway performance', type: 'output' }, { text: ' cat server.js - Output snippet of remote index server configuration', type: 'output' }, { text: ' keychain - Query keychain credentials loaded for target session', type: 'output' }, { text: ' clear - Wipe the terminal display buffer clean', type: 'output' }, ], ls: [ { text: 'drwxr-xr-x 3 root root 4096 Jul 6 12:00 controllers', type: 'output' }, { text: 'drwxr-xr-x 2 root root 4096 Jul 6 12:00 models', type: 'output' }, { text: 'drwxr-xr-x 2 root root 4096 Jul 6 12:00 routes', type: 'output' }, { text: '-rw-r--r-- 1 root root 280 Jul 6 11:34 .env', type: 'error' }, { text: '-rw-r--r-- 1 root root 1432 Jul 6 14:20 package.json', type: 'output' }, { text: '-rwxr-xr-x 1 root root 8412 Jul 6 15:43 server.js', type: 'success' }, ], 'docker ps': [ { text: 'CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS', type: 'success' }, { text: 'f87a2d12e9b0 node:18-alpine "docker-entrypoint.s…" 2 hours ago Up 2 hours 0.0.0.0:3000->3000/tcp', type: 'output' }, { text: 'c23e84bf9211 postgres:15-alpine "docker-entrypoint.s…" 5 hours ago Up 5 hours 0.0.0.0:5432->5432/tcp', type: 'output' }, { text: '78da12b84e0c redis:7-alpine "docker-entrypoint.s…" 10 hours ago Up 10 hours 0.0.0.0:6379->6379/tcp', type: 'output' }, ], 'uname -a': [ { text: 'Linux ' + tabName + ' 5.15.0-101-generic #111-Ubuntu SMP Wed Jul 6 21:27:00 UTC 2026 x86_64 GNU/Linux', type: 'output' }, ], 'cat server.js': [ { text: 'const express = require("express");', type: 'output' }, { text: 'const app = express();', type: 'output' }, { text: 'const PORT = process.env.PORT || 3000;', type: 'output' }, { text: 'app.get("/api/health", (req, res) => res.send({ status: "healthy" }));', type: 'output' }, { text: 'app.listen(PORT, () => console.log("Server active on cluster ingress"));', type: 'success' }, ], keychain: [ { text: 'Keychain Credential Mapping Selected:', type: 'success' }, { text: ' Active Key: id_ed25519_alex (ED25519 standard)', type: 'output' }, { text: ' Encryption: AES-256 GCM cryptokey payload', type: 'output' }, { text: ' Fingerprint: SHA256:7mP9K9+fVj5bW0vQ8zD1y2u3t4m5n6p7q8r9s0v1w2x', type: 'output' }, ], }; if (commands[clean]) { return commands[clean]; } if (clean.startsWith('ping')) { return [ { text: '64 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=12.4 ms', type: 'output' }, { text: '64 bytes from 8.8.8.8: icmp_seq=2 ttl=116 time=14.1 ms', type: 'output' }, { text: '64 bytes from 8.8.8.8: icmp_seq=3 ttl=116 time=11.8 ms', type: 'output' }, { text: '--- 8.8.8.8 ping statistics ---', type: 'success' }, { text: '3 packets transmitted, 3 received, 0% packet loss, rtt min/avg/max = 11.8/12.76/14.1 ms', type: 'success' }, ]; } return [{ text: `hostkeeper: command not found: "${cmd}". Type "help" to view custom commands list.`, type: 'error' }]; } Alpine.data('terminalManager', () => ({ tabs: [], activeTab: 0, histories: {}, command: '', get history() { const cur = this.tabs[this.activeTab]; return cur ? (this.histories[cur.id] || []) : []; }, init() { this.addTab(); }, addTab() { let host; if (selectedHostId) { host = hostOptions.find(h => h.id === selectedHostId) || hostOptions[0]; } if (!host) { host = hostOptions.length > 0 ? hostOptions[Math.floor(Math.random() * hostOptions.length)] : { id: 'h1', name: 'localhost', ip: '127.0.0.1' }; } const id = 'tab-' + Date.now() + '-' + Math.random().toString(36).slice(2, 6); this.tabs.push({ id, name: host.name, host: host.ip, connected: true }); this.activeTab = this.tabs.length - 1; this.histories[id] = [ { text: 'Connecting to ' + host.name + ' (' + host.ip + ') via port 22...', type: 'output' }, { text: 'Using identity keychain file: id_ed25519_alex (strength: SECURE)', type: 'output' }, { text: 'Welcome to Ubuntu 22.04 LTS (GNU/Linux 5.15.0-101-generic x86_64)', type: 'success' }, { text: 'System load: 0.12 | Processes: 104 | Memory: 32% used', type: 'output' }, { text: 'Type "help" to view custom interactive HostKeeper mock commands.', type: 'success' }, ]; this.$nextTick(() => { const out = document.getElementById('terminal-output'); if (out) out.scrollTop = out.scrollHeight; }); }, switchTab(i) { this.activeTab = i; this.$nextTick(() => { const out = document.getElementById('terminal-output'); if (out) out.scrollTop = out.scrollHeight; }); }, closeTab(i) { if (this.tabs.length <= 1) return; const id = this.tabs[i].id; this.tabs.splice(i, 1); delete this.histories[id]; if (this.activeTab >= this.tabs.length) this.activeTab = this.tabs.length - 1; }, submitCommand() { const cmd = this.command.trim(); if (!cmd) return; const cur = this.tabs[this.activeTab]; if (!cur) return; const id = cur.id; const lines = this.histories[id] || []; lines.push({ text: '$ ' + cmd, type: 'input' }); const output = processCommand(cmd, cur.name); this.histories[id] = lines.concat(output); this.command = ''; this.$nextTick(() => { const out = document.getElementById('terminal-output'); if (out) out.scrollTop = out.scrollHeight; }); }, insertCommand(cmd) { this.command = cmd; this.$nextTick(() => this.submitCommand()); }, clearBuffer() { const cur = this.tabs[this.activeTab]; if (!cur) return; this.histories[cur.id] = [ { text: 'Session log display buffer cleared manually.', type: 'output' }, { text: 'Type "help" to view interactive choices.', type: 'success' }, ]; }, })); });