Add 3 files
Browse files- README.md +7 -5
- index.html +480 -19
- prompts.txt +1 -0
README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
+
title: cli-sim-1
|
| 3 |
+
emoji: ⚛️
|
| 4 |
+
colorFrom: red
|
| 5 |
+
colorTo: red
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
tags:
|
| 9 |
+
- QwenSite
|
| 10 |
---
|
| 11 |
|
| 12 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
index.html
CHANGED
|
@@ -1,19 +1,480 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
| 6 |
+
<title>CLI Terminal Simulator</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;700&display=swap" rel="stylesheet">
|
| 9 |
+
<style>
|
| 10 |
+
body, html {
|
| 11 |
+
font-family: 'JetBrains Mono', monospace;
|
| 12 |
+
background-color: #0d1117;
|
| 13 |
+
color: #c9d1d9;
|
| 14 |
+
height: 100%;
|
| 15 |
+
margin: 0;
|
| 16 |
+
padding: 0;
|
| 17 |
+
overflow: hidden;
|
| 18 |
+
}
|
| 19 |
+
#output-area {
|
| 20 |
+
height: calc(100vh - 40px);
|
| 21 |
+
overflow-y: auto;
|
| 22 |
+
padding: 1rem;
|
| 23 |
+
font-size: 0.9rem;
|
| 24 |
+
white-space: pre-wrap;
|
| 25 |
+
display: flex;
|
| 26 |
+
flex-direction: column;
|
| 27 |
+
}
|
| 28 |
+
#input-line {
|
| 29 |
+
display: flex;
|
| 30 |
+
align-items: center;
|
| 31 |
+
padding: 0 1rem 1rem 1rem;
|
| 32 |
+
color: #58a6ff;
|
| 33 |
+
}
|
| 34 |
+
#prompt {
|
| 35 |
+
color: #58a6ff;
|
| 36 |
+
}
|
| 37 |
+
#command-input {
|
| 38 |
+
background: transparent;
|
| 39 |
+
border: none;
|
| 40 |
+
color: #c9d1d9;
|
| 41 |
+
outline: none;
|
| 42 |
+
font-family: 'JetBrains Mono', monospace;
|
| 43 |
+
font-size: 0.9rem;
|
| 44 |
+
width: 100%;
|
| 45 |
+
}
|
| 46 |
+
.cursor {
|
| 47 |
+
display: inline-block;
|
| 48 |
+
width: 8px;
|
| 49 |
+
height: 1em;
|
| 50 |
+
background-color: #c9d1d9;
|
| 51 |
+
animation: blink 1s step-end infinite;
|
| 52 |
+
margin-left: 2px;
|
| 53 |
+
}
|
| 54 |
+
@keyframes blink {
|
| 55 |
+
0%, 100% { opacity: 1; }
|
| 56 |
+
50% { opacity: 0; }
|
| 57 |
+
}
|
| 58 |
+
.cmd-user { color: #58a6ff; }
|
| 59 |
+
.cmd-output { color: #c9d1d9; margin-left: 2rem; white-space: pre-wrap; }
|
| 60 |
+
.cmd-error { color: #f85149; margin-left: 2rem; }
|
| 61 |
+
.highlight-green { color: #3fb950; }
|
| 62 |
+
.highlight-blue { color: #58a6ff; }
|
| 63 |
+
.highlight-yellow { color: #d29922; }
|
| 64 |
+
</style>
|
| 65 |
+
</head>
|
| 66 |
+
<body class="text-sm leading-tight">
|
| 67 |
+
<div id="app" class="h-full flex flex-col">
|
| 68 |
+
<!-- Output Area -->
|
| 69 |
+
<div id="output-area" class="flex-1 font-mono"></div>
|
| 70 |
+
|
| 71 |
+
<!-- Input Area -->
|
| 72 |
+
<div id="input-line">
|
| 73 |
+
<span id="prompt" class="mr-2">$</span>
|
| 74 |
+
<div id="command-input" contenteditable="true" spellcheck="false" autofocus></div>
|
| 75 |
+
<div class="cursor"></div>
|
| 76 |
+
</div>
|
| 77 |
+
</div>
|
| 78 |
+
|
| 79 |
+
<script>
|
| 80 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 81 |
+
const outputArea = document.getElementById('output-area');
|
| 82 |
+
const inputLine = document.getElementById('command-input');
|
| 83 |
+
const prompt = document.getElementById('prompt');
|
| 84 |
+
|
| 85 |
+
// Virtual File System (in-memory)
|
| 86 |
+
let vfs = {
|
| 87 |
+
'/': {
|
| 88 |
+
type: 'directory',
|
| 89 |
+
children: {
|
| 90 |
+
home: {
|
| 91 |
+
type: 'directory',
|
| 92 |
+
children: {
|
| 93 |
+
user: {
|
| 94 |
+
type: 'directory',
|
| 95 |
+
children: {
|
| 96 |
+
'profile.txt': {
|
| 97 |
+
type: 'file',
|
| 98 |
+
content: 'Hello, I am a simulated user profile.\nEnjoy the CLI experience!'
|
| 99 |
+
},
|
| 100 |
+
'notes.md': {
|
| 101 |
+
type: 'file',
|
| 102 |
+
content: '# My Notes\n- This is a simulated file system.\n- Try using `ls`, `cd`, `cat`, etc.'
|
| 103 |
+
}
|
| 104 |
+
}
|
| 105 |
+
}
|
| 106 |
+
}
|
| 107 |
+
},
|
| 108 |
+
'README.txt': {
|
| 109 |
+
type: 'file',
|
| 110 |
+
content: 'Welcome to the Web CLI Simulator v1.0\nType `help` to see available commands.'
|
| 111 |
+
}
|
| 112 |
+
}
|
| 113 |
+
}
|
| 114 |
+
};
|
| 115 |
+
|
| 116 |
+
// State
|
| 117 |
+
let currentPath = '/';
|
| 118 |
+
let commandHistory = JSON.parse(localStorage.getItem('cli-command-history') || '[]');
|
| 119 |
+
let historyIndex = -1; // For navigating history with arrow keys
|
| 120 |
+
let lastCommandScroll = null;
|
| 121 |
+
|
| 122 |
+
// DOM Utility Functions
|
| 123 |
+
const appendOutput = (text, className = '') => {
|
| 124 |
+
const line = document.createElement('div');
|
| 125 |
+
line.className = className;
|
| 126 |
+
line.textContent = text;
|
| 127 |
+
outputArea.appendChild(line);
|
| 128 |
+
outputArea.scrollTop = outputArea.scrollHeight; // Auto-scroll
|
| 129 |
+
lastCommandScroll = outputArea.scrollHeight;
|
| 130 |
+
};
|
| 131 |
+
|
| 132 |
+
const clearOutput = () => {
|
| 133 |
+
outputArea.innerHTML = '';
|
| 134 |
+
};
|
| 135 |
+
|
| 136 |
+
// Path Utilities
|
| 137 |
+
const resolvePath = (path) => {
|
| 138 |
+
if (path === '/') return '/';
|
| 139 |
+
const parts = path.split('/').filter(p => p && p !== '.');
|
| 140 |
+
const resolved = [];
|
| 141 |
+
for (const part of parts) {
|
| 142 |
+
if (part === '..') {
|
| 143 |
+
resolved.pop();
|
| 144 |
+
} else {
|
| 145 |
+
resolved.push(part);
|
| 146 |
+
}
|
| 147 |
+
}
|
| 148 |
+
return '/' + resolved.join('/');
|
| 149 |
+
};
|
| 150 |
+
|
| 151 |
+
const navigateToPath = (path) => {
|
| 152 |
+
const resolved = resolvePath(path);
|
| 153 |
+
const segments = resolved.slice(1).split('/').filter(p => p);
|
| 154 |
+
let curr = vfs['/'];
|
| 155 |
+
for (const seg of segments) {
|
| 156 |
+
if (curr.type !== 'directory' || !curr.children[seg]) {
|
| 157 |
+
return null;
|
| 158 |
+
}
|
| 159 |
+
curr = curr.children[seg];
|
| 160 |
+
}
|
| 161 |
+
currentPath = resolved;
|
| 162 |
+
return curr;
|
| 163 |
+
};
|
| 164 |
+
|
| 165 |
+
const listDirectory = (dir) => {
|
| 166 |
+
const items = Object.keys(dir.children || {});
|
| 167 |
+
return items.length > 0 ? items.join(' ') : '(empty)';
|
| 168 |
+
};
|
| 169 |
+
|
| 170 |
+
const getCurrentDir = () => {
|
| 171 |
+
return navigateToPath(currentPath);
|
| 172 |
+
};
|
| 173 |
+
|
| 174 |
+
const getAbsolutePath = (path) => {
|
| 175 |
+
if (path.startsWith('/')) {
|
| 176 |
+
return path;
|
| 177 |
+
}
|
| 178 |
+
return resolvePath(currentPath + '/' + path);
|
| 179 |
+
};
|
| 180 |
+
|
| 181 |
+
// Commands
|
| 182 |
+
const commands = {
|
| 183 |
+
help: () => {
|
| 184 |
+
const helpText = `
|
| 185 |
+
Available commands:
|
| 186 |
+
help - Show this help message
|
| 187 |
+
ls [dir] - List files and directories
|
| 188 |
+
cd <dir> - Change directory (.. for parent)
|
| 189 |
+
cat <file> - Display file content
|
| 190 |
+
echo <text> - Print the given text
|
| 191 |
+
clear - Clear the terminal screen
|
| 192 |
+
mkdir <dir> - Create a new directory
|
| 193 |
+
touch <file> - Create an empty file
|
| 194 |
+
rm <file/dir> - Remove a file or directory
|
| 195 |
+
pwd - Print working directory
|
| 196 |
+
history - Show command history
|
| 197 |
+
whoami - Display current user
|
| 198 |
+
date - Show current date and time
|
| 199 |
+
`.trim();
|
| 200 |
+
appendOutput(helpText, 'cmd-output');
|
| 201 |
+
},
|
| 202 |
+
|
| 203 |
+
ls: (args) => {
|
| 204 |
+
const targetPath = args.length > 0 ? getAbsolutePath(args[0]) : currentPath;
|
| 205 |
+
const dir = navigateToPath(targetPath);
|
| 206 |
+
if (!dir) {
|
| 207 |
+
appendOutput(`ls: cannot access '${args[0]}': No such file or directory`, 'cmd-error');
|
| 208 |
+
return;
|
| 209 |
+
}
|
| 210 |
+
if (dir.type !== 'directory') {
|
| 211 |
+
appendOutput(`ls: ${args[0]} is not a directory`, 'cmd-error');
|
| 212 |
+
return;
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
const items = Object.keys(dir.children || {});
|
| 216 |
+
if (items.length === 0) {
|
| 217 |
+
appendOutput('(empty)', 'cmd-output');
|
| 218 |
+
return;
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
const formatted = items.map(name => {
|
| 222 |
+
const item = dir.children[name];
|
| 223 |
+
if (item.type === 'directory') return `<span class="highlight-blue">${name}/</span>`;
|
| 224 |
+
return name;
|
| 225 |
+
}).join(' ');
|
| 226 |
+
|
| 227 |
+
const div = document.createElement('div');
|
| 228 |
+
div.className = 'cmd-output';
|
| 229 |
+
div.innerHTML = formatted;
|
| 230 |
+
outputArea.appendChild(div);
|
| 231 |
+
outputArea.scrollTop = outputArea.scrollHeight;
|
| 232 |
+
},
|
| 233 |
+
|
| 234 |
+
cd: (args) => {
|
| 235 |
+
if (args.length === 0) {
|
| 236 |
+
appendOutput('cd: missing operand', 'cmd-error');
|
| 237 |
+
return;
|
| 238 |
+
}
|
| 239 |
+
const target = args[0];
|
| 240 |
+
const newPath = getAbsolutePath(target);
|
| 241 |
+
const dir = navigateToPath(newPath);
|
| 242 |
+
if (!dir) {
|
| 243 |
+
appendOutput(`cd: no such directory: ${target}`, 'cmd-error');
|
| 244 |
+
return;
|
| 245 |
+
}
|
| 246 |
+
if (dir.type !== 'directory') {
|
| 247 |
+
appendOutput(`cd: not a directory: ${target}`, 'cmd-error');
|
| 248 |
+
return;
|
| 249 |
+
}
|
| 250 |
+
currentPath = newPath;
|
| 251 |
+
updatePrompt();
|
| 252 |
+
},
|
| 253 |
+
|
| 254 |
+
cat: (args) => {
|
| 255 |
+
if (args.length === 0) {
|
| 256 |
+
appendOutput('cat: missing file operand', 'cmd-error');
|
| 257 |
+
return;
|
| 258 |
+
}
|
| 259 |
+
const filePath = getAbsolutePath(args[0]);
|
| 260 |
+
const segments = filePath.slice(1).split('/').filter(p => p);
|
| 261 |
+
let curr = vfs['/'];
|
| 262 |
+
for (let i = 0; i < segments.length - 1; i++) {
|
| 263 |
+
if (curr.type !== 'directory' || !curr.children[segments[i]]) {
|
| 264 |
+
appendOutput(`cat: ${args[0]}: No such file or directory`, 'cmd-error');
|
| 265 |
+
return;
|
| 266 |
+
}
|
| 267 |
+
curr = curr.children[segments[i]];
|
| 268 |
+
}
|
| 269 |
+
const fileName = segments[segments.length - 1];
|
| 270 |
+
if (!curr.children[fileName]) {
|
| 271 |
+
appendOutput(`cat: ${args[0]}: No such file or directory`, 'cmd-error');
|
| 272 |
+
return;
|
| 273 |
+
}
|
| 274 |
+
const file = curr.children[fileName];
|
| 275 |
+
if (file.type !== 'file') {
|
| 276 |
+
appendOutput(`cat: ${args[0]}: Is a directory`, 'cmd-error');
|
| 277 |
+
return;
|
| 278 |
+
}
|
| 279 |
+
appendOutput(file.content, 'cmd-output');
|
| 280 |
+
},
|
| 281 |
+
|
| 282 |
+
echo: (args) => {
|
| 283 |
+
appendOutput(args.join(' '), 'cmd-output');
|
| 284 |
+
},
|
| 285 |
+
|
| 286 |
+
clear: () => {
|
| 287 |
+
clearOutput();
|
| 288 |
+
},
|
| 289 |
+
|
| 290 |
+
mkdir: (args) => {
|
| 291 |
+
if (args.length === 0) {
|
| 292 |
+
appendOutput('mkdir: missing operand', 'cmd-error');
|
| 293 |
+
return;
|
| 294 |
+
}
|
| 295 |
+
const dirPath = getAbsolutePath(args[0]);
|
| 296 |
+
const segments = dirPath.slice(1).split('/').filter(p => p);
|
| 297 |
+
const dirName = segments.pop();
|
| 298 |
+
let parentPath = '/' + segments.join('/');
|
| 299 |
+
if (segments.length === 0) parentPath = '/';
|
| 300 |
+
|
| 301 |
+
const parentDir = navigateToPath(parentPath);
|
| 302 |
+
if (!parentDir) {
|
| 303 |
+
appendOutput(`mkdir: cannot create directory '${args[0]}': No such file or directory`, 'cmd-error');
|
| 304 |
+
return;
|
| 305 |
+
}
|
| 306 |
+
if (parentDir.children[dirName]) {
|
| 307 |
+
appendOutput(`mkdir: cannot create directory '${args[0]}': File exists`, 'cmd-error');
|
| 308 |
+
return;
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
parentDir.children[dirName] = {
|
| 312 |
+
type: 'directory',
|
| 313 |
+
children: {}
|
| 314 |
+
};
|
| 315 |
+
appendOutput('', 'cmd-output'); // Blank line
|
| 316 |
+
},
|
| 317 |
+
|
| 318 |
+
touch: (args) => {
|
| 319 |
+
if (args.length === 0) {
|
| 320 |
+
appendOutput('touch: missing file operand', 'cmd-error');
|
| 321 |
+
return;
|
| 322 |
+
}
|
| 323 |
+
const filePath = getAbsolutePath(args[0]);
|
| 324 |
+
const segments = filePath.slice(1).split('/').filter(p => p);
|
| 325 |
+
const fileName = segments.pop();
|
| 326 |
+
let parentPath = '/' + segments.join('/');
|
| 327 |
+
if (segments.length === 0) parentPath = '/';
|
| 328 |
+
|
| 329 |
+
const parentDir = navigateToPath(parentPath);
|
| 330 |
+
if (!parentDir) {
|
| 331 |
+
appendOutput(`touch: cannot create file '${args[0]}': No such file or directory`, 'cmd-error');
|
| 332 |
+
return;
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
if (parentDir.children[fileName] && parentDir.children[fileName].type === 'directory') {
|
| 336 |
+
appendOutput(`touch: cannot create file '${args[0]}': Is a directory`, 'cmd-error');
|
| 337 |
+
return;
|
| 338 |
+
}
|
| 339 |
+
|
| 340 |
+
parentDir.children[fileName] = {
|
| 341 |
+
type: 'file',
|
| 342 |
+
content: ''
|
| 343 |
+
};
|
| 344 |
+
appendOutput('', 'cmd-output'); // Blank line
|
| 345 |
+
},
|
| 346 |
+
|
| 347 |
+
rm: (args) => {
|
| 348 |
+
if (args.length === 0) {
|
| 349 |
+
appendOutput('rm: missing operand', 'cmd-error');
|
| 350 |
+
return;
|
| 351 |
+
}
|
| 352 |
+
const targetPath = getAbsolutePath(args[0]);
|
| 353 |
+
const segments = targetPath.slice(1).split('/').filter(p => p);
|
| 354 |
+
const name = segments.pop();
|
| 355 |
+
let parentPath = '/' + segments.join('/');
|
| 356 |
+
if (segments.length === 0) parentPath = '/';
|
| 357 |
+
|
| 358 |
+
const parentDir = navigateToPath(parentPath);
|
| 359 |
+
if (!parentDir) {
|
| 360 |
+
appendOutput(`rm: failed to delete '${args[0]}': No such file or directory`, 'cmd-error');
|
| 361 |
+
return;
|
| 362 |
+
}
|
| 363 |
+
if (!parentDir.children[name]) {
|
| 364 |
+
appendOutput(`rm: cannot remove '${args[0]}': No such file or directory`, 'cmd-error');
|
| 365 |
+
return;
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
delete parentDir.children[name];
|
| 369 |
+
appendOutput('', 'cmd-output');
|
| 370 |
+
},
|
| 371 |
+
|
| 372 |
+
pwd: () => {
|
| 373 |
+
appendOutput(currentPath, 'cmd-output');
|
| 374 |
+
},
|
| 375 |
+
|
| 376 |
+
history: () => {
|
| 377 |
+
commandHistory.forEach((cmd, i) => {
|
| 378 |
+
appendOutput(`${i+1} ${cmd}`, 'cmd-output');
|
| 379 |
+
});
|
| 380 |
+
},
|
| 381 |
+
|
| 382 |
+
whoami: () => {
|
| 383 |
+
appendOutput('web-user', 'cmd-output');
|
| 384 |
+
},
|
| 385 |
+
|
| 386 |
+
date: () => {
|
| 387 |
+
const now = new Date();
|
| 388 |
+
appendOutput(now.toString(), 'cmd-output');
|
| 389 |
+
}
|
| 390 |
+
};
|
| 391 |
+
|
| 392 |
+
// Update prompt to show current path
|
| 393 |
+
const updatePrompt = () => {
|
| 394 |
+
prompt.textContent = `$ ${currentPath}`;
|
| 395 |
+
};
|
| 396 |
+
|
| 397 |
+
// Command Execution
|
| 398 |
+
const executeCommand = (input) => {
|
| 399 |
+
const trimmed = input.trim();
|
| 400 |
+
if (!trimmed) return;
|
| 401 |
+
|
| 402 |
+
// Add to history
|
| 403 |
+
commandHistory.push(trimmed);
|
| 404 |
+
localStorage.setItem('cli-command-history', JSON.stringify(commandHistory));
|
| 405 |
+
historyIndex = -1; // Reset history index
|
| 406 |
+
|
| 407 |
+
// Show command in output
|
| 408 |
+
appendOutput(`$ ${trimmed}`, 'cmd-user');
|
| 409 |
+
|
| 410 |
+
// Parse command
|
| 411 |
+
const [cmd, ...args] = trimmed.split(' ');
|
| 412 |
+
const commandFunc = commands[cmd];
|
| 413 |
+
|
| 414 |
+
if (commandFunc) {
|
| 415 |
+
commandFunc(args);
|
| 416 |
+
} else {
|
| 417 |
+
appendOutput(`Command not found: ${cmd}. Type 'help' for a list of commands.`, 'cmd-error');
|
| 418 |
+
}
|
| 419 |
+
};
|
| 420 |
+
|
| 421 |
+
// Event Listeners
|
| 422 |
+
inputLine.addEventListener('keydown', (e) => {
|
| 423 |
+
if (e.key === 'Enter') {
|
| 424 |
+
e.preventDefault();
|
| 425 |
+
const value = inputLine.textContent || '';
|
| 426 |
+
executeCommand(value);
|
| 427 |
+
inputLine.textContent = '';
|
| 428 |
+
} else if (e.key === 'ArrowUp') {
|
| 429 |
+
e.preventDefault();
|
| 430 |
+
if (historyIndex < commandHistory.length - 1) {
|
| 431 |
+
historyIndex++;
|
| 432 |
+
inputLine.textContent = commandHistory[commandHistory.length - 1 - historyIndex] || '';
|
| 433 |
+
inputLine.selectionStart = inputLine.selectionEnd = inputLine.textContent.length;
|
| 434 |
+
}
|
| 435 |
+
} else if (e.key === 'ArrowDown') {
|
| 436 |
+
e.preventDefault();
|
| 437 |
+
if (historyIndex > 0) {
|
| 438 |
+
historyIndex--;
|
| 439 |
+
inputLine.textContent = commandHistory[commandHistory.length - 1 - historyIndex] || '';
|
| 440 |
+
} else if (historyIndex === 0) {
|
| 441 |
+
historyIndex = -1;
|
| 442 |
+
inputLine.textContent = '';
|
| 443 |
+
}
|
| 444 |
+
}
|
| 445 |
+
});
|
| 446 |
+
|
| 447 |
+
// Focus input on click
|
| 448 |
+
outputArea.addEventListener('click', () => {
|
| 449 |
+
inputLine.focus();
|
| 450 |
+
});
|
| 451 |
+
|
| 452 |
+
// Initial welcome
|
| 453 |
+
appendOutput('Welcome to the Web CLI Simulator!', 'cmd-output');
|
| 454 |
+
appendOutput('Type `help` to get started.', 'cmd-output');
|
| 455 |
+
|
| 456 |
+
updatePrompt();
|
| 457 |
+
inputLine.focus();
|
| 458 |
+
|
| 459 |
+
// Save VFS to localStorage every 2 seconds (optional persistence)
|
| 460 |
+
setInterval(() => {
|
| 461 |
+
try {
|
| 462 |
+
localStorage.setItem('cli-vfs', JSON.stringify(vfs));
|
| 463 |
+
} catch (e) {
|
| 464 |
+
console.warn('Could not save VFS to localStorage:', e);
|
| 465 |
+
}
|
| 466 |
+
}, 2000);
|
| 467 |
+
|
| 468 |
+
// Load VFS from localStorage on start
|
| 469 |
+
try {
|
| 470 |
+
const saved = localStorage.getItem('cli-vfs');
|
| 471 |
+
if (saved) {
|
| 472 |
+
vfs = JSON.parse(saved);
|
| 473 |
+
}
|
| 474 |
+
} catch (e) {
|
| 475 |
+
console.warn('Could not load VFS from localStorage:', e);
|
| 476 |
+
}
|
| 477 |
+
});
|
| 478 |
+
</script>
|
| 479 |
+
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-qwensite.hf.space/logo.svg" alt="qwensite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-qwensite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >QwenSite</a> - 🧬 <a href="https://enzostvs-qwensite.hf.space?remix=dokii/cli-sim-1" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
| 480 |
+
</html>
|
prompts.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
## Stand-alone Web App CLI Simulation (React+Three.js) ### 1. Introduction This document outlines the specifications for a stand-alone web application designed to simulate a Command Line Interface (CLI) experience within a web browser. The application will be purely conceptual, requiring no backend infrastructure, and will leverage client-side technologies to mimic the look, feel, and basic functionality of a CLI. ### 2. Requirements * **Stand-alone:** The application must function entirely within the user's browser without requiring a server or backend connection. * **Web-based:** Accessible via a standard web browser. * **CLI Simulation:** Visually and interactively emulate a terminal or command-line environment. * **No Backend:** All processing, state management, and data storage must occur client-side. * **Conceptual:** Focus on demonstrating the *concept* of a web-based CLI, not on replicating a full-featured OS or complex application. ### 3. User Interface (UI) * **Layout:** A single-page application layout. * **Output Area:** A scrollable, read-only area displaying command history, outputs, and system messages. This area should visually resemble terminal output (e.g., monospace font, distinct text colors for commands, output, and errors). * **Input Area:** A text input field at the bottom, mimicking a command prompt, where users can type commands. It should display a prompt symbol (e.g., `> ` or `$ `). * **Cursor:** A blinking cursor within the input field. * **Styling:** CSS will be used to achieve a terminal-like appearance, including: * Background color (e.g., dark grey, black). * Text color (e.g., light grey, green, white). * Monospace font (e.g., Consolas, Monaco, Courier New). * Input field styling to blend with the output area. * **Interactivity:** * User input is captured upon pressing `Enter`. * The entered command is displayed in the output area, prefixed with the prompt symbol. * The input field is cleared after `Enter` is pressed. * Command output (or error messages) is displayed below the entered command in the output area. * Support for basic navigation (e.g., up/down arrow keys for command history). ### 4. Core Functionality & Data Flow * **Client-Side Technologies:** * **HTML:** Structure of the page (output area, input field). * **CSS:** Styling for terminal appearance. * **JavaScript:** Handles all logic: * **Input Parsing:** Capturing and parsing user commands. * **Command Mapping:** Associating command strings with specific JavaScript functions. * **State Management:** Maintaining application state (e.g., current directory, simulated file system, command history) in memory. * **Output Rendering:** Dynamically updating the DOM to display results. * **Virtual File System (VFS):** * A JavaScript object (e.g., nested objects or a Map) will simulate a file system structure (directories and files). * Operations like `ls`, `cd`, `cat`, `mkdir`, `touch`, `rm` will be implemented as JavaScript functions that manipulate this in-memory VFS. * **Command Execution Flow:** 1. User types a command in the input field and presses `Enter`. 2. JavaScript captures the command string. 3. The command is added to the command history and displayed in the output area. 4. The command string is parsed to identify the command name and its arguments. 5. A command handler function (mapped via JavaScript object/Map) is invoked. 6. The handler function interacts with the VFS and application state. 7. The handler function returns output (text, error message, or status). 8. The returned output is displayed in the output area. 9. Application state is updated if necessary. * **State Persistence (Optional):** * `localStorage` or `sessionStorage` can be used to persist the VFS and command history across page reloads, enhancing the simulation. ### 5. Conceptual Technical Insights * **No Backend:** Emphasizes client-side JavaScript's capability to manage complex application logic and state without server intervention. This is achieved through in-memory data structures and browser storage APIs. * **SQL-like Conceptualization:** While no actual SQL database is used, the *logic* of data manipulation (storing command history, managing state, representing file structures) can be conceptually mapped to SQL operations (INSERT, SELECT, UPDATE, DELETE on tables like `CommandHistory`, `AppState`, `FileSystem`). This provides a familiar paradigm for understanding data management, even in a client-side context. * **Libraries:** Libraries like `xterm.js` can be integrated to provide a more robust and feature-rich terminal emulation experience, handling rendering, input, and advanced terminal behaviors. * **SPA Architecture:** The application will follow a Single Page Application pattern, where JavaScript dynamically updates the content of a single HTML page, eliminating the need for full page reloads and providing a seamless user experience. ### 6. Example Commands (Conceptual) * `help`: Displays a list of available commands. * `ls`: Lists files and directories in the current VFS directory. * `cd <directory>`: Changes the current directory in the VFS. * `cat <file>`: Displays the content of a file in the VFS. * `echo <text>`: Prints the provided text to the output. * `clear`: Clears the output area. * `history`: Displays the command history.
|