feat(chat): CLI easter egg with 17 commands + Konami dev-mode + matrix rain
This commit is contained in:
parent
33dfb3410b
commit
ee8d313403
5 changed files with 601 additions and 0 deletions
|
|
@ -1,6 +1,25 @@
|
||||||
{
|
{
|
||||||
"site": "jaeswift.xyz",
|
"site": "jaeswift.xyz",
|
||||||
"entries": [
|
"entries": [
|
||||||
|
{
|
||||||
|
"version": "1.37.1",
|
||||||
|
"date": "20/04/2026",
|
||||||
|
"category": "FEATURE",
|
||||||
|
"title": "JAE-AI CLI Easter Egg — Local Pseudo-Shell",
|
||||||
|
"changes": [
|
||||||
|
"JAE-AI chat now detects messages starting with / and handles them locally as a fake CLI shell — never hits the Venice API, all 100% client-side JavaScript",
|
||||||
|
"New js/chat-cli.js + css/chat-cli.css — 17 built-in commands: /help /ls /cat <file> /whoami /uptime /uname -a /date /ping <host> /sudo <cmd> /rm -rf / /hack <target> /matrix /clear /exit /fortune /history /neofetch",
|
||||||
|
"Virtual filesystem: /cat about.md|projects.json|skills.md|secrets.enc|mascot.txt|whoami.txt — with glitchy ASCII art ACCESS DENIED screen on secrets.enc",
|
||||||
|
"/whoami pulls real data from /api/visitor/scan; /uptime pulls from /api/telemetry/overview; /neofetch shows ASCII dragon with browser/OS/screen data",
|
||||||
|
"/matrix toggles a full-screen green Katakana matrix-rain canvas overlay (opacity 18%, 16px JetBrains Mono, var(--status-green))",
|
||||||
|
"/hack runs hollywood-style fake progress bars with payload injection drama before revealing it was all fake",
|
||||||
|
"/rm -rf / shows an ASCII destruction sequence then restores from backup with a cheeky message",
|
||||||
|
"Unknown commands route to: command not found: /<cmd>. Type /help for available commands.",
|
||||||
|
"Persistent /history ring-buffer (50 entries) stored in localStorage.jaeCliHist",
|
||||||
|
"BONUS: Konami code (↑↑↓↓←→←→BA) unlocks DEVELOPER MODE — amber badge top-right + extra commands: /api (list real endpoints), /curl <url> (actually fetch public URLs, 2KB truncated), /geo (pull live 24h country breakdown from telemetry)",
|
||||||
|
"chat.js sendMessage() patched to intercept /-prefix messages before hitting /api/chat — user bubble gets $ shell prompt, response styled in terminal-green monospace"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.37.0",
|
"version": "1.37.0",
|
||||||
"date": "20/04/2026",
|
"date": "20/04/2026",
|
||||||
|
|
|
||||||
42
css/chat-cli.css
Normal file
42
css/chat-cli.css
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/* ===================================================
|
||||||
|
JAESWIFT.XYZ — JAE-AI CLI output styling
|
||||||
|
=================================================== */
|
||||||
|
|
||||||
|
.chat-msg-cli {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
}
|
||||||
|
.chat-msg-cli .chat-msg-label {
|
||||||
|
color: var(--warning);
|
||||||
|
}
|
||||||
|
.chat-msg-cli .chat-msg-body {
|
||||||
|
color: var(--status-green);
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
white-space: pre-wrap;
|
||||||
|
line-height: 1.4;
|
||||||
|
font-size: 12.5px;
|
||||||
|
text-shadow: 0 0 4px #00cc3340;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-msg-user-cli .chat-msg-label {
|
||||||
|
color: var(--status-green);
|
||||||
|
}
|
||||||
|
.chat-msg-user-cli .chat-msg-body {
|
||||||
|
color: #e8e8e8;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.chat-msg-user-cli .chat-msg-body::before {
|
||||||
|
content: '$ ';
|
||||||
|
color: var(--status-green);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
#devModeBadge:hover {
|
||||||
|
background: rgba(201,162,39,0.15) !important;
|
||||||
|
box-shadow: 0 0 22px rgba(201,162,39,0.6) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.chat-msg-cli .chat-msg-body { font-size: 11px; }
|
||||||
|
#devModeBadge { font-size: 9px !important; top: 62px !important; padding: 4px 9px !important; }
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
<link rel="stylesheet" href="/css/style.css">
|
<link rel="stylesheet" href="/css/style.css">
|
||||||
<link rel="stylesheet" href="/css/chat-memory.css">
|
<link rel="stylesheet" href="/css/chat-memory.css">
|
||||||
<link rel="stylesheet" href="/css/scan-visitor.css">
|
<link rel="stylesheet" href="/css/scan-visitor.css">
|
||||||
|
<link rel="stylesheet" href="/css/chat-cli.css">
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&family=Orbitron:wght@400;500;600;700;800;900&family=Share+Tech+Mono&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&family=Orbitron:wght@400;500;600;700;800;900&family=Share+Tech+Mono&display=swap" rel="stylesheet">
|
||||||
|
|
@ -588,6 +589,7 @@
|
||||||
<script src="/js/wallet-connect.js"></script>
|
<script src="/js/wallet-connect.js"></script>
|
||||||
<script src="/js/nav.js"></script>
|
<script src="/js/nav.js"></script>
|
||||||
<script src="/js/chat-memory.js"></script>
|
<script src="/js/chat-memory.js"></script>
|
||||||
|
<script src="/js/chat-cli.js"></script>
|
||||||
<script src="/js/chat.js"></script>
|
<script src="/js/chat.js"></script>
|
||||||
<script src="/js/globe.js"></script>
|
<script src="/js/globe.js"></script>
|
||||||
<script src="/js/processes.js"></script>
|
<script src="/js/processes.js"></script>
|
||||||
|
|
|
||||||
510
js/chat-cli.js
Normal file
510
js/chat-cli.js
Normal file
|
|
@ -0,0 +1,510 @@
|
||||||
|
/* ===================================================
|
||||||
|
JAESWIFT.XYZ — JAE-AI CLI Easter Egg
|
||||||
|
Local pseudo-shell handled in the JAE-AI chat panel.
|
||||||
|
Intercepts messages starting with '/'.
|
||||||
|
=================================================== */
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const MAX_HISTORY = 50;
|
||||||
|
const HIST_KEY = 'jaeCliHist';
|
||||||
|
let cmdHistory = [];
|
||||||
|
let devMode = false;
|
||||||
|
let matrixActive = false;
|
||||||
|
|
||||||
|
// Load history
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(HIST_KEY);
|
||||||
|
if (raw) cmdHistory = JSON.parse(raw) || [];
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
function saveHistory() {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(HIST_KEY, JSON.stringify(cmdHistory.slice(-MAX_HISTORY)));
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Virtual FS ──────────────────────────────────
|
||||||
|
const VFS = {
|
||||||
|
'about.md': [
|
||||||
|
'# JAESWIFT // OPERATOR FILE',
|
||||||
|
'',
|
||||||
|
'Codename: JAE',
|
||||||
|
'Location: Manchester, United Kingdom',
|
||||||
|
'Operator since: 2008',
|
||||||
|
'',
|
||||||
|
'Full-stack engineer, cyber-curious, builds things.',
|
||||||
|
'Specialisms: Node / Python / Linux / nginx / Solana',
|
||||||
|
'',
|
||||||
|
'This site is my HUD. Built by hand, deployed by git, watched by me.',
|
||||||
|
].join('\n'),
|
||||||
|
|
||||||
|
'projects.json': JSON.stringify({
|
||||||
|
'jaeswift.xyz': 'This site — military CRT HUD, Flask+vanilla',
|
||||||
|
'matty.lol': 'Crypto/Solana toolkit (Node/Express)',
|
||||||
|
'contraband-depot': 'FMHY mirror, 24 categories, 16k+ links',
|
||||||
|
'recon-awesomelist': '28 sectors / 135k items, weekly sync',
|
||||||
|
'unredacted-vault': '114+ declassified PDFs (MOD/CIA/etc)',
|
||||||
|
'radar': 'RSS aggregator (HN/Reddit/Lobsters)',
|
||||||
|
'sitrep': 'Daily AI briefing generator',
|
||||||
|
'telemetry': 'Live ops command centre'
|
||||||
|
}, null, 2),
|
||||||
|
|
||||||
|
'skills.md': [
|
||||||
|
'# FIELD LOADOUT',
|
||||||
|
'',
|
||||||
|
'## LANGS',
|
||||||
|
' - Python, JavaScript/Node, TypeScript, Rust, Bash, SQL',
|
||||||
|
'',
|
||||||
|
'## STACKS',
|
||||||
|
' - Flask, Express, React, Solana/Anchor, Docker, systemd',
|
||||||
|
'',
|
||||||
|
'## INFRA',
|
||||||
|
' - nginx, Debian, PostgreSQL, Redis, cron, fail2ban',
|
||||||
|
'',
|
||||||
|
'## OPS',
|
||||||
|
' - VPS ops, CI/CD via Gitea, observability, hardening'
|
||||||
|
].join('\n'),
|
||||||
|
|
||||||
|
'secrets.enc': [
|
||||||
|
'',
|
||||||
|
' ░█████╗░░█████╗░░█████╗░███████╗░██████╗░██████╗',
|
||||||
|
' ██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔════╝██╔════╝',
|
||||||
|
' ███████║██║░░╚═╝██║░░╚═╝█████╗░░╚█████╗░╚█████╗░',
|
||||||
|
' ██╔══██║██║░░██╗██║░░██╗██╔══╝░░░╚═══██╗░╚═══██╗',
|
||||||
|
' ██║░░██║╚█████╔╝╚█████╔╝███████╗██████╔╝██████╔╝',
|
||||||
|
' ╚═╝░░╚═╝░╚════╝░░╚════╝░╚══════╝╚═════╝░╚═════╝░',
|
||||||
|
'',
|
||||||
|
' ▓▒░ ACCESS DENIED ░▒▓',
|
||||||
|
' File encrypted with AES-4096-QUANTUM-ROT13.',
|
||||||
|
' Authorisation required. >> /sudo',
|
||||||
|
].join('\n'),
|
||||||
|
|
||||||
|
'mascot.txt': [
|
||||||
|
' ___ ___',
|
||||||
|
' ,-" `. ," `-,',
|
||||||
|
' / _ \\_____/ _ \\',
|
||||||
|
' | (o) ` ` (o) |',
|
||||||
|
' \\ \\_._ _._/ /',
|
||||||
|
' `._ `----\' _.\'',
|
||||||
|
' `~---------~\'',
|
||||||
|
' // JAE MASCOT //',
|
||||||
|
' Black dragon, on duty.'
|
||||||
|
].join('\n'),
|
||||||
|
|
||||||
|
'whoami.txt': '$USER — check /whoami for your details.'
|
||||||
|
};
|
||||||
|
|
||||||
|
// ─── Helpers ─────────────────────────────────────
|
||||||
|
function fmt(lines) { return Array.isArray(lines) ? lines.join('\n') : lines; }
|
||||||
|
|
||||||
|
function pad(n, len) {
|
||||||
|
const s = String(n);
|
||||||
|
return s.length >= len ? s : ' '.repeat(len - s.length) + s;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fakeProgress(label, steps, delay) {
|
||||||
|
const out = [];
|
||||||
|
for (let i = 1; i <= steps; i++) {
|
||||||
|
const pct = Math.floor((i / steps) * 100);
|
||||||
|
const filled = '█'.repeat(Math.floor(pct / 5));
|
||||||
|
const empty = '░'.repeat(20 - filled.length);
|
||||||
|
out.push(`${label} [${filled}${empty}] ${pct}%`);
|
||||||
|
// intentionally not awaited — output comes as a block
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Commands ────────────────────────────────────
|
||||||
|
const commands = {};
|
||||||
|
|
||||||
|
commands.help = function () {
|
||||||
|
const base = [
|
||||||
|
'JAE-AI TERMINAL — available commands:',
|
||||||
|
'',
|
||||||
|
' /help show this help',
|
||||||
|
' /ls list virtual files',
|
||||||
|
' /cat <file> print file contents',
|
||||||
|
' /whoami show your visitor fingerprint',
|
||||||
|
' /uptime show site uptime',
|
||||||
|
' /uname kernel/system info',
|
||||||
|
' /date current date/time',
|
||||||
|
' /ping <host> fake ping sweep',
|
||||||
|
' /sudo <cmd> attempt privilege escalation',
|
||||||
|
' /rm -rf / don\'t do it',
|
||||||
|
' /hack <target> hollywood hacking simulator',
|
||||||
|
' /matrix toggle matrix rain',
|
||||||
|
' /clear clear the chat',
|
||||||
|
' /exit try to leave',
|
||||||
|
' /fortune random sitrep quip',
|
||||||
|
' /history show last commands',
|
||||||
|
' /neofetch system summary ASCII',
|
||||||
|
];
|
||||||
|
if (devMode) {
|
||||||
|
base.push('');
|
||||||
|
base.push(' [DEVELOPER MODE ACTIVE]');
|
||||||
|
base.push(' /api list real API endpoints');
|
||||||
|
base.push(' /curl <url> actually fetch a URL');
|
||||||
|
base.push(' /geo show GEO INTEL from telemetry');
|
||||||
|
}
|
||||||
|
base.push('');
|
||||||
|
base.push('Anything not prefixed with / goes to JAE-AI.');
|
||||||
|
return fmt(base);
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.ls = function () {
|
||||||
|
return fmt([
|
||||||
|
'total 6',
|
||||||
|
'-rw-r--r-- 1 jae jae 412 apr 20 01:24 about.md',
|
||||||
|
'-rw-r--r-- 1 jae jae 528 apr 20 01:24 projects.json',
|
||||||
|
'-rw-r--r-- 1 jae jae 394 apr 20 01:24 skills.md',
|
||||||
|
'-r-------- 1 jae jae 999 apr 20 01:24 secrets.enc',
|
||||||
|
'-rw-r--r-- 1 jae jae 210 apr 20 01:24 mascot.txt',
|
||||||
|
'-rw-r--r-- 1 jae jae 42 apr 20 01:24 whoami.txt'
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.cat = function (args) {
|
||||||
|
const name = args[0];
|
||||||
|
if (!name) return 'cat: missing operand — try /cat about.md';
|
||||||
|
if (VFS[name] != null) return VFS[name];
|
||||||
|
return `cat: ${name}: No such file or directory`;
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.whoami = async function () {
|
||||||
|
try {
|
||||||
|
const r = await fetch('/api/visitor/scan');
|
||||||
|
if (!r.ok) throw new Error('scan unavailable');
|
||||||
|
const d = await r.json();
|
||||||
|
return fmt([
|
||||||
|
`operator: ${d.ip_masked}`,
|
||||||
|
`geolocation: ${d.city ? d.city + ', ' : ''}${d.country} ${d.country_flag || ''}`,
|
||||||
|
`network: ${d.isp}`,
|
||||||
|
`browser: ${d.browser} ${d.browser_version || ''}`,
|
||||||
|
`os: ${d.os} ${d.os_version || ''}`,
|
||||||
|
`device: ${d.device}`,
|
||||||
|
`threat: ${d.threat_level} — ${d.threat_reason}`,
|
||||||
|
'',
|
||||||
|
'you are a visitor. welcome.'
|
||||||
|
]);
|
||||||
|
} catch (e) {
|
||||||
|
return 'scan service unavailable. try again in a moment.';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.uptime = async function () {
|
||||||
|
try {
|
||||||
|
const r = await fetch('/api/telemetry/overview');
|
||||||
|
const d = await r.json();
|
||||||
|
const up = (d.system && d.system.uptime) || d.uptime || 'unknown';
|
||||||
|
const load = (d.system && d.system.load_1) || '—';
|
||||||
|
const users = 'many';
|
||||||
|
const now = new Date().toLocaleTimeString('en-GB');
|
||||||
|
return fmt([
|
||||||
|
` ${now} up ${up}, ${users} users, load average: ${load}`,
|
||||||
|
` HQ: Manchester // jaeswift-api.service ● ONLINE`
|
||||||
|
]);
|
||||||
|
} catch (e) {
|
||||||
|
return `up since boot — tired but operational`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.uname = function (args) {
|
||||||
|
if (args[0] === '-a') {
|
||||||
|
return 'Linux jaeswift 6.1.0-jaeswift #1 SMP PREEMPT_DYNAMIC 2026-04-20 x86_64 GNU/Linux';
|
||||||
|
}
|
||||||
|
return 'Linux';
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.date = function () {
|
||||||
|
return new Date().toUTCString();
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.ping = function (args) {
|
||||||
|
const host = args[0] || 'jaeswift.xyz';
|
||||||
|
const out = [`PING ${host} (10.0.0.1) 56(84) bytes of data.`];
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
const t = (10 + Math.random() * 40).toFixed(2);
|
||||||
|
out.push(`64 bytes from ${host}: icmp_seq=${i+1} ttl=54 time=${t} ms`);
|
||||||
|
}
|
||||||
|
out.push('');
|
||||||
|
out.push(`--- ${host} ping statistics ---`);
|
||||||
|
out.push('4 packets transmitted, 4 received, 0% packet loss, time 3006ms');
|
||||||
|
return fmt(out);
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.sudo = function (args) {
|
||||||
|
if (!args.length) return 'usage: /sudo <command>';
|
||||||
|
return fmt([
|
||||||
|
`[sudo] password for operator: ****`,
|
||||||
|
``,
|
||||||
|
`sudo: ACCESS DENIED — nice try.`,
|
||||||
|
`This incident will be reported... actually, no it won\'t.`
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.rm = function (args) {
|
||||||
|
if (args.join(' ') === '-rf /' || args.join(' ').startsWith('-rf /')) {
|
||||||
|
return fmt([
|
||||||
|
' __ __',
|
||||||
|
' / \\_/ \\ 💥 FORMATTING /dev/sda ...',
|
||||||
|
' \\_( • )_/ 💥 WIPING /home ...',
|
||||||
|
' //( )\\\\ 💥 DELETING /etc/passwd ...',
|
||||||
|
'',
|
||||||
|
' ERROR: The file system is screaming.',
|
||||||
|
' ███████████░░░░░░░░░ 58%',
|
||||||
|
'',
|
||||||
|
' ... just kidding.',
|
||||||
|
' SYSTEM RESTORED FROM BACKUP. Nice try, operator.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return `rm: refuse to do whatever that is`;
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.hack = function (args) {
|
||||||
|
const target = args.join(' ') || 'the-gibson';
|
||||||
|
return fmt([
|
||||||
|
`>>> TARGETING ${target}...`,
|
||||||
|
`>>> BYPASSING FIREWALL... [████████████░░░░] 72%`,
|
||||||
|
`>>> CRACKING PASSWORD... [████████████████] 100%`,
|
||||||
|
`>>> INJECTING PAYLOAD... [████████████████] 100%`,
|
||||||
|
`>>> COVERING TRACKS... [████████████████] 100%`,
|
||||||
|
``,
|
||||||
|
`>>> CONNECTION ESTABLISHED.`,
|
||||||
|
`>>> ACCESS GRANTED TO ${target.toUpperCase()}.`,
|
||||||
|
``,
|
||||||
|
`... just kidding lol. nothing was hacked.`,
|
||||||
|
`If you came here looking for real offsec — go read /cat skills.md and touch grass.`
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.matrix = function () {
|
||||||
|
matrixActive = !matrixActive;
|
||||||
|
toggleMatrix(matrixActive);
|
||||||
|
return matrixActive
|
||||||
|
? 'Matrix rain enabled. Follow the white rabbit.'
|
||||||
|
: 'Matrix rain disabled. Back to the desert of the real.';
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.clear = function () {
|
||||||
|
const cm = document.getElementById('chatMessages');
|
||||||
|
if (cm) cm.innerHTML = '';
|
||||||
|
return null; // nothing to print
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.exit = function () {
|
||||||
|
return fmt([
|
||||||
|
'logout',
|
||||||
|
'',
|
||||||
|
'NICE TRY. You don\'t leave that easily.',
|
||||||
|
'JAE-AI resumes normal operation.'
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const FORTUNES = [
|
||||||
|
'SITREP: quiet on the wire. unusual.',
|
||||||
|
'SITREP: nothing is fine. everything is broken. proceed.',
|
||||||
|
'SITREP: coffee low. deploy anyway.',
|
||||||
|
'SITREP: the logs know. the logs always know.',
|
||||||
|
'SITREP: git status is a lifestyle.',
|
||||||
|
'SITREP: ship it friday. regret it monday.',
|
||||||
|
'SITREP: 99 bugs on the wall, patch one down, 117 on the wall.',
|
||||||
|
'SITREP: if it works on the VPS, the VPS is now production.',
|
||||||
|
'SITREP: the only safe deploy is no deploy.',
|
||||||
|
'SITREP: trust nothing. grep everything.',
|
||||||
|
];
|
||||||
|
|
||||||
|
commands.fortune = function () {
|
||||||
|
return FORTUNES[Math.floor(Math.random() * FORTUNES.length)];
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.history = function () {
|
||||||
|
if (!cmdHistory.length) return '(no history yet)';
|
||||||
|
const recent = cmdHistory.slice(-10);
|
||||||
|
return recent.map((c, i) => ` ${pad(cmdHistory.length - recent.length + i + 1, 4)} ${c}`).join('\n');
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.neofetch = function () {
|
||||||
|
const cc = (navigator.language || 'en').toUpperCase();
|
||||||
|
const ua = navigator.userAgent || '';
|
||||||
|
let browser = 'Unknown';
|
||||||
|
if (/firefox/i.test(ua)) browser = 'Firefox';
|
||||||
|
else if (/edg/i.test(ua)) browser = 'Edge';
|
||||||
|
else if (/chrome/i.test(ua)) browser = 'Chrome';
|
||||||
|
else if (/safari/i.test(ua)) browser = 'Safari';
|
||||||
|
return fmt([
|
||||||
|
' ▄███████▄ operator@jaeswift.xyz',
|
||||||
|
' ██░░░░░░░██ ----------------------',
|
||||||
|
' ██░░░░░░░██ OS: JAESWIFT/6.1.0 x86_64',
|
||||||
|
' ██░██░██░██ Host: Manchester HQ',
|
||||||
|
' ██░░░░░░░██ Kernel: CRT-tactical-v2',
|
||||||
|
' ██░░░░░██ Uptime: 24/7/365',
|
||||||
|
' ███████ Shell: /bin/jaesh',
|
||||||
|
' █ █ Resolution: ' + screen.width + 'x' + screen.height,
|
||||||
|
' ██ ██ Terminal: JAE-AI',
|
||||||
|
' ██ ██ Browser: ' + browser,
|
||||||
|
' Locale: ' + cc,
|
||||||
|
' CPU: 18-core @ spicy GHz',
|
||||||
|
' Memory: 96GB tactical',
|
||||||
|
' Theme: mil-green/CRT/cyberpunk',
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ─── Dev-mode commands ──────────────────────────
|
||||||
|
commands.api = async function () {
|
||||||
|
if (!devMode) return 'command not found. try /help';
|
||||||
|
const endpoints = [
|
||||||
|
'/api/visitor/scan',
|
||||||
|
'/api/visitor/recent-arcs',
|
||||||
|
'/api/leaderboards',
|
||||||
|
'/api/telemetry/overview',
|
||||||
|
'/api/telemetry/history',
|
||||||
|
'/api/telemetry/geo',
|
||||||
|
'/api/telemetry/visitors',
|
||||||
|
'/api/telemetry/nginx-tail',
|
||||||
|
'/api/telemetry/alerts',
|
||||||
|
'/api/stats',
|
||||||
|
'/api/navigation',
|
||||||
|
'/api/changelog',
|
||||||
|
'/api/chat (POST)',
|
||||||
|
'/api/contraband',
|
||||||
|
'/api/sitrep/latest',
|
||||||
|
'/api/radar'
|
||||||
|
];
|
||||||
|
return 'JAESWIFT API endpoints (dev-mode):\n\n ' + endpoints.join('\n ');
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.curl = async function (args) {
|
||||||
|
if (!devMode) return 'command not found. try /help';
|
||||||
|
const url = args[0];
|
||||||
|
if (!url) return 'usage: /curl <url>';
|
||||||
|
try {
|
||||||
|
const r = await fetch(url);
|
||||||
|
const text = (await r.text()).slice(0, 2000);
|
||||||
|
return `HTTP ${r.status} ${r.statusText}\ncontent-type: ${r.headers.get('content-type') || 'n/a'}\n\n${text}${text.length >= 2000 ? '\n...[truncated]' : ''}`;
|
||||||
|
} catch (e) {
|
||||||
|
return `curl: (6) ${e.message}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.geo = async function () {
|
||||||
|
if (!devMode) return 'command not found. try /help';
|
||||||
|
try {
|
||||||
|
const r = await fetch('/api/telemetry/geo');
|
||||||
|
const d = await r.json();
|
||||||
|
if (!Array.isArray(d) || !d.length) return 'GEO INTEL: no data.';
|
||||||
|
return 'GEO INTEL (24h):\n\n' + d.slice(0, 15).map((row, i) =>
|
||||||
|
` ${pad(i+1, 2)}. ${(row.country_code || 'XX').padEnd(3)} ${(row.country_name || 'Unknown').padEnd(22)} ${pad(row.count || 0, 5)}`
|
||||||
|
).join('\n');
|
||||||
|
} catch (e) {
|
||||||
|
return 'telemetry unavailable.';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ─── Matrix rain overlay ─────────────────────────
|
||||||
|
let matrixCanvas = null;
|
||||||
|
let matrixRAF = null;
|
||||||
|
function toggleMatrix(on) {
|
||||||
|
if (on) {
|
||||||
|
matrixCanvas = document.createElement('canvas');
|
||||||
|
matrixCanvas.id = 'matrixRain';
|
||||||
|
Object.assign(matrixCanvas.style, {
|
||||||
|
position: 'fixed', inset: '0', width: '100%', height: '100%',
|
||||||
|
pointerEvents: 'none', zIndex: '7', opacity: '0.18',
|
||||||
|
});
|
||||||
|
document.body.appendChild(matrixCanvas);
|
||||||
|
const ctx = matrixCanvas.getContext('2d');
|
||||||
|
function resize() {
|
||||||
|
matrixCanvas.width = window.innerWidth;
|
||||||
|
matrixCanvas.height = window.innerHeight;
|
||||||
|
}
|
||||||
|
resize();
|
||||||
|
window.addEventListener('resize', resize);
|
||||||
|
const chars = 'アイウエオカキクケコサシスセソタチツテトナニヌネノ01JAESWIFT'.split('');
|
||||||
|
const size = 16;
|
||||||
|
const cols = Math.floor(matrixCanvas.width / size);
|
||||||
|
const drops = new Array(cols).fill(1);
|
||||||
|
function draw() {
|
||||||
|
ctx.fillStyle = 'rgba(0, 0, 0, 0.06)';
|
||||||
|
ctx.fillRect(0, 0, matrixCanvas.width, matrixCanvas.height);
|
||||||
|
ctx.fillStyle = '#00cc33';
|
||||||
|
ctx.font = size + 'px JetBrains Mono, monospace';
|
||||||
|
for (let i = 0; i < drops.length; i++) {
|
||||||
|
const ch = chars[Math.floor(Math.random() * chars.length)];
|
||||||
|
ctx.fillText(ch, i * size, drops[i] * size);
|
||||||
|
if (drops[i] * size > matrixCanvas.height && Math.random() > 0.975) drops[i] = 0;
|
||||||
|
drops[i]++;
|
||||||
|
}
|
||||||
|
matrixRAF = requestAnimationFrame(draw);
|
||||||
|
}
|
||||||
|
draw();
|
||||||
|
} else {
|
||||||
|
if (matrixRAF) cancelAnimationFrame(matrixRAF);
|
||||||
|
if (matrixCanvas) matrixCanvas.remove();
|
||||||
|
matrixCanvas = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Konami Code → Developer Mode ────────────────
|
||||||
|
const KONAMI = ['ArrowUp','ArrowUp','ArrowDown','ArrowDown','ArrowLeft','ArrowRight','ArrowLeft','ArrowRight','b','a'];
|
||||||
|
let kBuf = [];
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
kBuf.push(e.key);
|
||||||
|
if (kBuf.length > KONAMI.length) kBuf.shift();
|
||||||
|
const match = kBuf.length === KONAMI.length && kBuf.every((k, i) => k.toLowerCase() === KONAMI[i].toLowerCase());
|
||||||
|
if (match && !devMode) {
|
||||||
|
devMode = true;
|
||||||
|
// Add a floating dev badge
|
||||||
|
const badge = document.createElement('div');
|
||||||
|
badge.id = 'devModeBadge';
|
||||||
|
Object.assign(badge.style, {
|
||||||
|
position: 'fixed', top: '68px', right: '16px', zIndex: '900',
|
||||||
|
background: 'var(--bg-panel)', border: '1px solid var(--warning)',
|
||||||
|
color: 'var(--warning)', padding: '6px 12px', fontFamily: 'var(--font-mono)',
|
||||||
|
fontSize: '11px', letterSpacing: '1.5px', cursor: 'pointer',
|
||||||
|
boxShadow: '0 0 14px rgba(201,162,39,0.4)',
|
||||||
|
});
|
||||||
|
badge.innerHTML = '⚡ DEVELOPER MODE // UNLOCKED';
|
||||||
|
badge.title = 'Click to disable';
|
||||||
|
badge.addEventListener('click', () => {
|
||||||
|
devMode = false; badge.remove();
|
||||||
|
});
|
||||||
|
document.body.appendChild(badge);
|
||||||
|
try { window.dispatchEvent(new CustomEvent('jae-dev-mode-on')); } catch (err) {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─── Entry point — handle a /-command ───────────
|
||||||
|
async function handle(raw) {
|
||||||
|
const trimmed = raw.trim();
|
||||||
|
if (!trimmed.startsWith('/')) return { handled: false };
|
||||||
|
|
||||||
|
const parts = trimmed.slice(1).split(/\s+/);
|
||||||
|
const cmd = (parts[0] || '').toLowerCase();
|
||||||
|
const args = parts.slice(1);
|
||||||
|
|
||||||
|
cmdHistory.push(trimmed);
|
||||||
|
if (cmdHistory.length > MAX_HISTORY) cmdHistory = cmdHistory.slice(-MAX_HISTORY);
|
||||||
|
saveHistory();
|
||||||
|
|
||||||
|
if (!cmd) return { handled: true, output: '' };
|
||||||
|
|
||||||
|
const fn = commands[cmd];
|
||||||
|
if (!fn) {
|
||||||
|
return { handled: true, output: `command not found: /${cmd}. type /help for available commands.` };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await fn(args);
|
||||||
|
return { handled: true, output: (result == null ? '' : String(result)) };
|
||||||
|
} catch (e) {
|
||||||
|
return { handled: true, output: `error: ${e.message}` };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.__jaeCLI = {
|
||||||
|
handle: handle,
|
||||||
|
commands: commands,
|
||||||
|
isDev: function () { return devMode; },
|
||||||
|
};
|
||||||
|
})();
|
||||||
28
js/chat.js
28
js/chat.js
|
|
@ -127,6 +127,34 @@
|
||||||
const text = chatInput.value.trim();
|
const text = chatInput.value.trim();
|
||||||
if (!text || isWaiting) return;
|
if (!text || isWaiting) return;
|
||||||
|
|
||||||
|
// ─── CLI interception ───
|
||||||
|
if (text.startsWith('/') && window.__jaeCLI && typeof window.__jaeCLI.handle === 'function') {
|
||||||
|
isWaiting = true;
|
||||||
|
chatInput.value = '';
|
||||||
|
const userBubble = addMessage('user', text);
|
||||||
|
const userMsg = userBubble && userBubble.parentElement;
|
||||||
|
if (userMsg) userMsg.classList.add('chat-msg-user-cli');
|
||||||
|
try {
|
||||||
|
const res = await window.__jaeCLI.handle(text);
|
||||||
|
if (res && res.handled) {
|
||||||
|
if (res.output) {
|
||||||
|
const body = addMessage('assistant', '');
|
||||||
|
const msgEl = body && body.parentElement;
|
||||||
|
if (msgEl) msgEl.classList.add('chat-msg-cli');
|
||||||
|
body.textContent = res.output;
|
||||||
|
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
const body = addMessage('assistant', 'cli error: ' + e.message);
|
||||||
|
const msgEl = body && body.parentElement;
|
||||||
|
if (msgEl) msgEl.classList.add('chat-msg-cli');
|
||||||
|
}
|
||||||
|
isWaiting = false;
|
||||||
|
chatInput.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
isWaiting = true;
|
isWaiting = true;
|
||||||
chatInput.value = '';
|
chatInput.value = '';
|
||||||
chatStatus.textContent = '● PROCESSING';
|
chatStatus.textContent = '● PROCESSING';
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue