|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Terminal { |
|
|
constructor() { |
|
|
this.terminals = new Map(); |
|
|
this.commandHistory = []; |
|
|
this.historyIndex = -1; |
|
|
this.currentDirectory = '~'; |
|
|
|
|
|
|
|
|
this.fileSystem = { |
|
|
'~': { |
|
|
type: 'dir', |
|
|
contents: { |
|
|
'projects': { type: 'dir', contents: { |
|
|
'sneaky-cat-proxy.md': { type: 'file', content: 'Project info...' }, |
|
|
'cat-photo-gallery.md': { type: 'file', content: 'Gallery info...' }, |
|
|
'robo-cat-manager.md': { type: 'file', content: 'Bot manager info...' } |
|
|
}}, |
|
|
'documents': { type: 'dir', contents: { |
|
|
'resume.pdf': { type: 'file', content: 'Professional resume' }, |
|
|
'cat-wisdom.txt': { type: 'file', content: 'Ancient cat knowledge' } |
|
|
}}, |
|
|
'pictures': { type: 'dir', contents: { |
|
|
'profile.jpg': { type: 'file', content: 'Profile picture' }, |
|
|
'cats': { type: 'dir', contents: { |
|
|
'fluffy.jpg': { type: 'file', content: 'A fluffy cat' }, |
|
|
'whiskers.png': { type: 'file', content: 'Cat with whiskers' } |
|
|
}} |
|
|
}}, |
|
|
'README.md': { type: 'file', content: 'Welcome to CatOS!' } |
|
|
} |
|
|
} |
|
|
}; |
|
|
} |
|
|
|
|
|
initialize(terminalId, core) { |
|
|
this.core = core; |
|
|
|
|
|
const terminal = { |
|
|
id: terminalId, |
|
|
element: document.querySelector(`[data-terminal-id="${terminalId}"]`), |
|
|
input: document.getElementById(`terminal-input-${terminalId}`), |
|
|
content: document.getElementById(`terminal-content-${terminalId}`), |
|
|
prompt: document.getElementById(`prompt-${terminalId}`) |
|
|
}; |
|
|
|
|
|
if (!terminal.input || !terminal.content) return; |
|
|
|
|
|
this.terminals.set(terminalId, terminal); |
|
|
this.setupTerminalEvents(terminalId); |
|
|
terminal.input.focus(); |
|
|
} |
|
|
|
|
|
setupTerminalEvents(terminalId) { |
|
|
const terminal = this.terminals.get(terminalId); |
|
|
if (!terminal) return; |
|
|
|
|
|
terminal.input.addEventListener('keydown', (e) => { |
|
|
switch(e.key) { |
|
|
case 'Enter': |
|
|
this.handleCommand(terminalId); |
|
|
break; |
|
|
case 'ArrowUp': |
|
|
e.preventDefault(); |
|
|
this.navigateHistory(terminalId, -1); |
|
|
break; |
|
|
case 'ArrowDown': |
|
|
e.preventDefault(); |
|
|
this.navigateHistory(terminalId, 1); |
|
|
break; |
|
|
case 'Tab': |
|
|
e.preventDefault(); |
|
|
this.handleTabCompletion(terminalId); |
|
|
break; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
terminal.content.addEventListener('click', () => { |
|
|
terminal.input.focus(); |
|
|
}); |
|
|
} |
|
|
|
|
|
handleCommand(terminalId) { |
|
|
const terminal = this.terminals.get(terminalId); |
|
|
if (!terminal) return; |
|
|
|
|
|
const command = terminal.input.value.trim(); |
|
|
if (!command) return; |
|
|
|
|
|
|
|
|
this.commandHistory.push(command); |
|
|
this.historyIndex = this.commandHistory.length; |
|
|
|
|
|
|
|
|
this.addTerminalLine(terminal.content, `${this.getPromptText()} ${command}`, 'terminal-prompt'); |
|
|
|
|
|
|
|
|
const [cmd, ...args] = command.split(' '); |
|
|
this.executeCommand(terminal.content, cmd.toLowerCase(), args); |
|
|
|
|
|
|
|
|
terminal.input.value = ''; |
|
|
terminal.content.scrollTop = terminal.content.scrollHeight; |
|
|
} |
|
|
|
|
|
executeCommand(content, cmd, args) { |
|
|
switch(cmd) { |
|
|
case 'help': |
|
|
this.terminalHelp(content); |
|
|
break; |
|
|
case 'clear': |
|
|
this.clearTerminal(content); |
|
|
break; |
|
|
case 'ls': |
|
|
this.terminalLs(content, args[0]); |
|
|
break; |
|
|
case 'cd': |
|
|
this.terminalCd(content, args[0]); |
|
|
break; |
|
|
case 'pwd': |
|
|
this.terminalPwd(content); |
|
|
break; |
|
|
case 'cat': |
|
|
this.terminalCat(content, args[0]); |
|
|
break; |
|
|
case 'whoami': |
|
|
this.terminalWhoami(content, this.getVisitorInfo()); |
|
|
break; |
|
|
case 'date': |
|
|
this.terminalDate(content); |
|
|
break; |
|
|
case 'echo': |
|
|
this.terminalEcho(content, args.join(' ')); |
|
|
break; |
|
|
case 'meow': |
|
|
this.terminalMeow(content, args.join(' ')); |
|
|
break; |
|
|
case 'purr': |
|
|
this.terminalPurr(content); |
|
|
break; |
|
|
case 'scratch': |
|
|
this.terminalScratch(content); |
|
|
break; |
|
|
case 'nap': |
|
|
this.terminalNap(content); |
|
|
break; |
|
|
case 'fortune': |
|
|
this.terminalFortune(content); |
|
|
break; |
|
|
case 'ps': |
|
|
this.terminalPs(content, args); |
|
|
break; |
|
|
case 'uptime': |
|
|
this.terminalUptime(content); |
|
|
break; |
|
|
case 'curl': |
|
|
this.terminalCurl(content, args[0]); |
|
|
break; |
|
|
case 'git': |
|
|
this.terminalGit(content, args); |
|
|
break; |
|
|
case 'npm': |
|
|
this.terminalNpm(content, args); |
|
|
break; |
|
|
case 'history': |
|
|
this.terminalHistory(content); |
|
|
break; |
|
|
case 'exit': |
|
|
case 'quit': |
|
|
this.terminalExit(content); |
|
|
break; |
|
|
default: |
|
|
this.terminalCommandNotFound(content, cmd); |
|
|
} |
|
|
} |
|
|
|
|
|
getPromptText() { |
|
|
return `cat@catos:${this.currentDirectory}$`; |
|
|
} |
|
|
|
|
|
addTerminalLine(content, text, className = 'terminal-text') { |
|
|
const line = document.createElement('div'); |
|
|
line.className = 'terminal-line'; |
|
|
line.innerHTML = `<span class="${className}">${text}</span>`; |
|
|
content.appendChild(line); |
|
|
} |
|
|
|
|
|
addTerminalOutput(content, text) { |
|
|
const line = document.createElement('div'); |
|
|
line.className = 'terminal-line'; |
|
|
line.innerHTML = `<span class="terminal-output">${text}</span>`; |
|
|
content.appendChild(line); |
|
|
} |
|
|
|
|
|
clearTerminal(content) { |
|
|
content.innerHTML = ''; |
|
|
this.addTerminalLine(content, 'Terminal cleared! Ready for more cat commands! 🐱', 'terminal-success'); |
|
|
} |
|
|
|
|
|
terminalHelp(content) { |
|
|
const helpText = ` |
|
|
<span class="terminal-category">📁 Navigation:</span> |
|
|
ls [path] - List directory contents |
|
|
cd [directory] - Change directory |
|
|
pwd - Show current directory |
|
|
cat [file] - Display file contents |
|
|
|
|
|
<span class="terminal-category">🔍 System:</span> |
|
|
whoami - Display visitor information |
|
|
ps aux - Show running processes |
|
|
uptime - System uptime |
|
|
date - Current date and time |
|
|
history - Command history |
|
|
clear - Clear terminal |
|
|
|
|
|
<span class="terminal-category">🌐 Network:</span> |
|
|
curl [url] - Fetch web content |
|
|
git [command] - Git operations |
|
|
npm [command] - NPM operations |
|
|
|
|
|
<span class="terminal-category">🐱 Cat Commands:</span> |
|
|
meow [message] - Cat responses |
|
|
purr - Show happiness level |
|
|
scratch - Stress relief |
|
|
nap - Take a quick break |
|
|
fortune - Cat wisdom |
|
|
|
|
|
<span class="terminal-category">💡 Tips:</span> |
|
|
Use ↑/↓ arrows for command history |
|
|
Try: cat projects/sneaky-cat-proxy.md |
|
|
Pro tip: Type 'm' anywhere for surprise meows! 😸 |
|
|
`; |
|
|
this.addTerminalOutput(content, helpText); |
|
|
} |
|
|
|
|
|
terminalWhoami(content, visitorInfo) { |
|
|
const info = ` |
|
|
<span class="terminal-category">🕵️ Visitor Detective Results:</span> |
|
|
┌─────────────────────────────────────┐ |
|
|
│ Browser: ${visitorInfo.browser} |
|
|
│ Platform: ${visitorInfo.platform} |
|
|
│ Screen: ${visitorInfo.screenWidth}x${visitorInfo.screenHeight} |
|
|
│ Language: ${visitorInfo.language} |
|
|
│ Visit Time: ${new Date(visitorInfo.visitTime).toLocaleString()} |
|
|
└─────────────────────────────────────┘ |
|
|
<span class="terminal-success">*purrs* Nice to meet you, fellow human! 🐱</span> |
|
|
`; |
|
|
this.addTerminalOutput(content, info); |
|
|
} |
|
|
|
|
|
getVisitorInfo() { |
|
|
return { |
|
|
browser: navigator.userAgent.split(' ').pop().split('/')[0] || 'Unknown', |
|
|
platform: navigator.platform || 'Unknown', |
|
|
screenWidth: screen.width, |
|
|
screenHeight: screen.height, |
|
|
language: navigator.language || 'Unknown', |
|
|
visitTime: Date.now() |
|
|
}; |
|
|
} |
|
|
|
|
|
terminalLs(content, path) { |
|
|
const targetPath = path || this.currentDirectory; |
|
|
const contents = this.getDirectoryContents(targetPath); |
|
|
|
|
|
if (!contents) { |
|
|
this.addTerminalOutput(content, `ls: cannot access '${targetPath}': No such file or directory 😿`); |
|
|
return; |
|
|
} |
|
|
|
|
|
let output = `<span class="terminal-category">📂 Contents of ${targetPath}:</span>\n`; |
|
|
contents.forEach(item => { |
|
|
const type = item.type === 'dir' ? '<span class="terminal-directory">DIR</span>' : '<span class="terminal-file">FILE</span>'; |
|
|
output += `${item.icon} ${type} ${item.name}\n`; |
|
|
}); |
|
|
|
|
|
this.addTerminalOutput(content, output); |
|
|
} |
|
|
|
|
|
getDirectoryContents(path) { |
|
|
|
|
|
let current = this.fileSystem['~']; |
|
|
|
|
|
if (path !== '~' && path !== '.') { |
|
|
const parts = path.replace(/^~\//, '').split('/').filter(p => p); |
|
|
for (const part of parts) { |
|
|
if (current.contents && current.contents[part]) { |
|
|
current = current.contents[part]; |
|
|
} else { |
|
|
return null; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if (current.type !== 'dir') return null; |
|
|
|
|
|
|
|
|
const contents = []; |
|
|
if (current.contents) { |
|
|
for (const [name, item] of Object.entries(current.contents)) { |
|
|
contents.push({ |
|
|
name, |
|
|
type: item.type, |
|
|
icon: item.type === 'dir' ? '📁' : '📄' |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
return contents; |
|
|
} |
|
|
|
|
|
terminalCd(content, path) { |
|
|
if (!path || path === '~') { |
|
|
this.currentDirectory = '~'; |
|
|
this.addTerminalOutput(content, `<span class="terminal-success">Changed to home directory 🏠</span>`); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
if (path === '..') { |
|
|
if (this.currentDirectory !== '~') { |
|
|
const parts = this.currentDirectory.split('/'); |
|
|
parts.pop(); |
|
|
this.currentDirectory = parts.join('/') || '~'; |
|
|
this.addTerminalOutput(content, `<span class="terminal-success">Moved up one directory 📁</span>`); |
|
|
} else { |
|
|
this.addTerminalOutput(content, `Already at root directory! 🏠`); |
|
|
} |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
const contents = this.getDirectoryContents(this.currentDirectory); |
|
|
const targetDir = contents?.find(item => item.name === path && item.type === 'dir'); |
|
|
|
|
|
if (targetDir) { |
|
|
this.currentDirectory = this.currentDirectory === '~' ? `~/${path}` : `${this.currentDirectory}/${path}`; |
|
|
this.addTerminalOutput(content, `<span class="terminal-success">Changed to ${this.currentDirectory} 📁</span>`); |
|
|
} else { |
|
|
this.addTerminalOutput(content, `cd: ${path}: No such directory 😿`); |
|
|
} |
|
|
|
|
|
|
|
|
this.terminals.forEach(terminal => { |
|
|
if (terminal.prompt) { |
|
|
terminal.prompt.textContent = this.getPromptText(); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
terminalPwd(content) { |
|
|
this.addTerminalOutput(content, `<span class="terminal-success">${this.currentDirectory}</span>`); |
|
|
} |
|
|
|
|
|
terminalCat(content, filename) { |
|
|
if (!filename) { |
|
|
this.addTerminalOutput(content, 'cat: missing file operand 🙀\nUsage: cat <filename>'); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
if (filename.includes('sneaky-cat-proxy')) { |
|
|
const project = this.core.appManager.projects['sneaky-cat-proxy']; |
|
|
this.addTerminalOutput(content, this.formatProjectInfo(project)); |
|
|
} else if (filename.includes('cat-photo-gallery')) { |
|
|
const project = this.core.appManager.projects['cat-photo-gallery']; |
|
|
this.addTerminalOutput(content, this.formatProjectInfo(project)); |
|
|
} else if (filename.includes('robo-cat-manager')) { |
|
|
const project = this.core.appManager.projects['robo-cat-manager']; |
|
|
this.addTerminalOutput(content, this.formatProjectInfo(project)); |
|
|
} else { |
|
|
this.addTerminalOutput(content, `cat: ${filename}: No such file or directory 😿`); |
|
|
} |
|
|
} |
|
|
|
|
|
formatProjectInfo(project) { |
|
|
return ` |
|
|
<span class="terminal-category">${project.icon} ${project.title}</span> |
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
|
|
|
|
|
<span class="terminal-success">Description:</span> |
|
|
${project.description} |
|
|
|
|
|
<span class="terminal-success">Technologies:</span> |
|
|
${project.technologies.map(tech => `• ${tech}`).join('\n')} |
|
|
|
|
|
<span class="terminal-success">Features:</span> |
|
|
${project.features.map(feature => `🐾 ${feature}`).join('\n')} |
|
|
|
|
|
<span class="terminal-success">Links:</span> |
|
|
• GitHub: ${project.github} |
|
|
• Demo: ${project.demo} |
|
|
|
|
|
<span class="terminal-category">*purrs approvingly* 😸</span> |
|
|
`; |
|
|
} |
|
|
|
|
|
terminalDate(content) { |
|
|
const now = new Date(); |
|
|
const dateString = now.toLocaleString('en-US', { |
|
|
weekday: 'long', |
|
|
year: 'numeric', |
|
|
month: 'long', |
|
|
day: 'numeric', |
|
|
hour: '2-digit', |
|
|
minute: '2-digit', |
|
|
second: '2-digit', |
|
|
timeZoneName: 'short' |
|
|
}); |
|
|
|
|
|
this.addTerminalOutput(content, `<span class="terminal-success">${dateString}</span>`); |
|
|
} |
|
|
|
|
|
terminalEcho(content, message) { |
|
|
this.addTerminalOutput(content, message || ''); |
|
|
} |
|
|
|
|
|
|
|
|
terminalMeow(content, message) { |
|
|
const catResponses = [ |
|
|
"🐱 *meows back* Purrfect!", |
|
|
"😸 *purrs* That's interesting!", |
|
|
"😺 *head bumps* I agree!", |
|
|
"🙀 *surprised meow* Really?!", |
|
|
"😻 *affectionate meow* Aww!", |
|
|
"😹 *laughing meow* Haha!", |
|
|
"😾 *grumpy meow* Hmph!" |
|
|
]; |
|
|
|
|
|
if (message) { |
|
|
const response = catResponses[Math.floor(Math.random() * catResponses.length)]; |
|
|
this.addTerminalOutput(content, `You said: "${message}"\n${response}`); |
|
|
} else { |
|
|
this.addTerminalOutput(content, catResponses[Math.floor(Math.random() * catResponses.length)]); |
|
|
} |
|
|
} |
|
|
|
|
|
terminalPurr(content) { |
|
|
const happiness = Math.floor(Math.random() * 100) + 1; |
|
|
const purrLevel = happiness > 80 ? "MAXIMUM PURR" : happiness > 60 ? "Happy purrs" : happiness > 40 ? "Content purrs" : "Quiet purrs"; |
|
|
|
|
|
this.addTerminalOutput(content, ` |
|
|
<span class="terminal-category">😸 Current Happiness Level: ${happiness}%</span> |
|
|
Status: ${purrLevel} |
|
|
Mood: ${happiness > 70 ? "😻 Ecstatic" : happiness > 50 ? "😊 Happy" : "😐 Neutral"} |
|
|
|
|
|
*${purrLevel.toLowerCase()}* 🐾 |
|
|
`); |
|
|
} |
|
|
|
|
|
terminalScratch(content) { |
|
|
this.addTerminalOutput(content, ` |
|
|
<span class="terminal-category">🐾 *scratch scratch*</span> |
|
|
Ahh, that's better! Stress levels reduced. |
|
|
Your virtual scratching post has been used. |
|
|
|
|
|
<span class="terminal-success">+10 Comfort Points! 😌</span> |
|
|
`); |
|
|
} |
|
|
|
|
|
terminalNap(content) { |
|
|
this.addTerminalOutput(content, ` |
|
|
<span class="terminal-category">😴 Taking a quick cat nap...</span> |
|
|
|
|
|
*curls up in a sunny spot* |
|
|
|
|
|
Zzz... 💤 |
|
|
|
|
|
<span class="terminal-success">Refreshed and ready! Energy restored! 🐱</span> |
|
|
`); |
|
|
} |
|
|
|
|
|
terminalFortune(content) { |
|
|
const fortunes = [ |
|
|
'🐾 A warm laptop keyboard is worth two in the bush.', |
|
|
'🐱 The best code is written at 3 AM with a cat on your keyboard.', |
|
|
'😸 In the kingdom of bugs, the debugger is king.', |
|
|
'🎯 A feature is only as good as its documentation... said no cat ever.', |
|
|
'💻 The cloud is just someone else\'s computer, probably with better WiFi.', |
|
|
'🐾 Remember: There are no mistakes, only happy little bugs.', |
|
|
'🐱 The cloud is just other people\'s litter boxes.' |
|
|
]; |
|
|
|
|
|
const fortune = fortunes[Math.floor(Math.random() * fortunes.length)]; |
|
|
this.addTerminalOutput(content, `<span class="terminal-category">🔮 Cat Fortune:</span>\n${fortune}`); |
|
|
} |
|
|
|
|
|
terminalPs(content, args) { |
|
|
const processes = ` |
|
|
<span class="terminal-category">🔄 CatOS Process Status:</span> |
|
|
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND |
|
|
cat 1337 15.2 8.5 245760 32156 pts/0 Sl+ 09:30 0:42 /usr/bin/coffee-maker |
|
|
cat 2020 12.1 4.2 128000 16384 pts/1 S 09:32 0:15 /usr/bin/yarn-ball-tracker |
|
|
cat 3000 8.7 2.1 64000 8192 pts/2 R 09:35 0:08 /usr/bin/mouse-detector |
|
|
cat 4040 5.3 1.8 32000 4096 pts/3 S 09:38 0:03 /usr/bin/nap-scheduler |
|
|
rafael 9999 98.5 75.2 2048000 234567 pts/5 R+ 09:35 5:67 /usr/bin/coding-furiously |
|
|
|
|
|
<span class="terminal-success">Current mood: Caffeinated and ready to code! ☕</span> |
|
|
`; |
|
|
this.addTerminalOutput(content, processes); |
|
|
} |
|
|
|
|
|
terminalUptime(content) { |
|
|
const uptime = ` |
|
|
<span class="terminal-category">⏱️ System Uptime:</span> |
|
|
Developer: 5+ years of coding experience |
|
|
Coffee Machine: 3 hours since last refill ☕ |
|
|
Cat OS: 42 days, 13 hours, 37 minutes (no crashes!) |
|
|
Motivation Level: 87% (pretty good for a Monday!) |
|
|
Purr Engine: Running at optimal frequency 😸 |
|
|
|
|
|
<span class="terminal-success">Load average: 1.33, 7.77, 42.00 (that's normal for a cat) 📊</span> |
|
|
`; |
|
|
this.addTerminalOutput(content, uptime); |
|
|
} |
|
|
|
|
|
terminalCurl(content, url) { |
|
|
if (!url) { |
|
|
this.addTerminalOutput(content, 'curl: no URL specified 🙀\nUsage: curl <url>'); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
this.addTerminalOutput(content, `<span class="terminal-category">🌐 Fetching ${url}...</span>`); |
|
|
|
|
|
setTimeout(() => { |
|
|
if (url.includes('github.com')) { |
|
|
this.addTerminalOutput(content, ` |
|
|
<span class="terminal-success">✅ Connected successfully!</span> |
|
|
Repository found: Lots of cat-themed code! 😸 |
|
|
Stars: ⭐⭐⭐⭐⭐ (purr-fect rating) |
|
|
Issues: 3 (all related to insufficient treats) |
|
|
`); |
|
|
} else { |
|
|
this.addTerminalOutput(content, ` |
|
|
<span class="terminal-success">✅ Response received!</span> |
|
|
Status: 200 OK 😺 |
|
|
Content-Type: text/purr-fect |
|
|
Cat-Approval: 100% |
|
|
`); |
|
|
} |
|
|
}, 1000); |
|
|
} |
|
|
|
|
|
terminalGit(content, args) { |
|
|
const subcommand = args[0] || 'status'; |
|
|
|
|
|
switch(subcommand) { |
|
|
case 'status': |
|
|
this.addTerminalOutput(content, ` |
|
|
<span class="terminal-category">📊 Git Status:</span> |
|
|
On branch main |
|
|
Your branch is up to date with 'origin/main'. |
|
|
|
|
|
Changes not staged for commit: |
|
|
modified: src/cat-behavior.js |
|
|
modified: config/treats.json |
|
|
|
|
|
Untracked files: |
|
|
hairball.log |
|
|
|
|
|
<span class="terminal-success">*purrs* Everything looks good! 🐾</span> |
|
|
`); |
|
|
break; |
|
|
case 'log': |
|
|
this.addTerminalOutput(content, ` |
|
|
<span class="terminal-category">📝 Git Log:</span> |
|
|
commit a1b2c3d (HEAD -> main, origin/main) |
|
|
Author: Cat Developer <cat@catos.dev> |
|
|
Date: Today |
|
|
|
|
|
Fix: Improved treat dispensing algorithm 🍪 |
|
|
|
|
|
commit e4f5g6h |
|
|
Author: Cat Developer <cat@catos.dev> |
|
|
Date: Yesterday |
|
|
|
|
|
Feature: Added nap scheduling system 😴 |
|
|
`); |
|
|
break; |
|
|
default: |
|
|
this.addTerminalOutput(content, `git ${subcommand}: Not implemented yet, but it sounds purr-fessional! 🐱💻`); |
|
|
} |
|
|
} |
|
|
|
|
|
terminalNpm(content, args) { |
|
|
const subcommand = args[0] || 'help'; |
|
|
|
|
|
switch(subcommand) { |
|
|
case 'install': |
|
|
this.addTerminalOutput(content, ` |
|
|
<span class="terminal-category">📦 Installing cat-packages...</span> |
|
|
|
|
|
+ catnip@4.2.0 |
|
|
+ yarn-ball@1.3.7 |
|
|
+ treat-dispenser@2.1.0 |
|
|
+ purr-engine@8.0.1 |
|
|
|
|
|
<span class="terminal-success">✅ All packages installed successfully! 😸</span> |
|
|
Note: Remember to pet your dependencies regularly. |
|
|
`); |
|
|
break; |
|
|
case 'start': |
|
|
this.addTerminalOutput(content, ` |
|
|
<span class="terminal-category">🚀 Starting development server...</span> |
|
|
|
|
|
> CatOS@9.0.0 start |
|
|
> cat-dev-server --purr |
|
|
|
|
|
Local: http://localhost:3000 🐾 |
|
|
Network: http://192.168.1.100:3000 |
|
|
`); |
|
|
break; |
|
|
case 'run': |
|
|
this.addTerminalOutput(content, `Available scripts: start, build, test, purr, nap`); |
|
|
break; |
|
|
default: |
|
|
this.addTerminalOutput(content, `npm ${subcommand}: Command not found. Try 'npm run purr' instead! 😹`); |
|
|
} |
|
|
} |
|
|
|
|
|
terminalHistory(content) { |
|
|
if (this.commandHistory.length === 0) { |
|
|
this.addTerminalOutput(content, 'No commands in history yet! 📜'); |
|
|
return; |
|
|
} |
|
|
|
|
|
let output = '<span class="terminal-category">📚 Command History:</span>\n'; |
|
|
this.commandHistory.forEach((cmd, index) => { |
|
|
output += `${index + 1}. ${cmd}\n`; |
|
|
}); |
|
|
|
|
|
this.addTerminalOutput(content, output); |
|
|
} |
|
|
|
|
|
terminalExit(content) { |
|
|
this.addTerminalOutput(content, ` |
|
|
<span class="terminal-category">👋 Goodbye!</span> |
|
|
Thanks for using CatOS Terminal! |
|
|
*purrs farewell* 😸 |
|
|
|
|
|
<span class="terminal-success">Tip: Close the window to fully exit, or keep coding! 🐾</span> |
|
|
`); |
|
|
} |
|
|
|
|
|
terminalCommandNotFound(content, cmd) { |
|
|
const suggestions = [ |
|
|
"Maybe you meant 'meow'? 🐱", |
|
|
"Try 'help' for available commands! 📖", |
|
|
"That's not a valid cat command! 😹", |
|
|
"*confused cat noises* 🙀", |
|
|
"Command not found in the litter box! 📦" |
|
|
]; |
|
|
|
|
|
const suggestion = suggestions[Math.floor(Math.random() * suggestions.length)]; |
|
|
this.addTerminalOutput(content, `${cmd}: command not found\n${suggestion}`); |
|
|
} |
|
|
|
|
|
|
|
|
navigateHistory(terminalId, direction) { |
|
|
const terminal = this.terminals.get(terminalId); |
|
|
if (!terminal || this.commandHistory.length === 0) return; |
|
|
|
|
|
this.historyIndex += direction; |
|
|
|
|
|
if (this.historyIndex < 0) { |
|
|
this.historyIndex = 0; |
|
|
} else if (this.historyIndex >= this.commandHistory.length) { |
|
|
this.historyIndex = this.commandHistory.length; |
|
|
terminal.input.value = ''; |
|
|
return; |
|
|
} |
|
|
|
|
|
terminal.input.value = this.commandHistory[this.historyIndex]; |
|
|
} |
|
|
|
|
|
|
|
|
handleTabCompletion(terminalId) { |
|
|
const terminal = this.terminals.get(terminalId); |
|
|
if (!terminal) return; |
|
|
|
|
|
const input = terminal.input.value; |
|
|
const commands = ['help', 'clear', 'ls', 'cd', 'pwd', 'cat', 'whoami', 'date', 'echo', |
|
|
'meow', 'purr', 'scratch', 'nap', 'fortune', 'ps', 'uptime', 'curl', |
|
|
'git', 'npm', 'history', 'exit']; |
|
|
|
|
|
const matches = commands.filter(cmd => cmd.startsWith(input)); |
|
|
|
|
|
if (matches.length === 1) { |
|
|
terminal.input.value = matches[0]; |
|
|
} else if (matches.length > 1) { |
|
|
this.addTerminalOutput(terminal.content, `Possible completions: ${matches.join(', ')}`); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
window.CatOSTerminal = new Terminal(); |