A browser-based Unix/Linux command emulator with vi editor support.
- Common Unix commands (ls, cd, cat, mkdir, rm, etc.)
- Add and modify commands
- Customizable filesystem
- Vi/Vim editor with modal editing
- Tab completion
- Command history
- Pipe and redirection support
- Wildcard expansion (
*and?) - Custom command support
npm install unix-shell-jsIf you're working locally and want to use this library in another project:
cd ../unix-shell-js
npm install
npm run build
npm link
cd ../your-project
npm link unix-shell-jsnpm run build- Compile TypeScript to JavaScript (outputs todist/) and copy to demonpm run copy-to-demo- Copy built files todocs/directory for GitHub Pages demonpm run watch- Watch mode for development (auto-recompiles on changes)npm run prepublishOnly- Automatically runs before publishing to npm
npm test- Run all testsnpm run test:watch- Run tests in watch modenpm run test:coverage- Run tests with coverage report
src/- TypeScript source filesindex.ts- Main Unix Shell implementationvi-editor.ts- Vi/Vim editorexample-files.ts- Example filesystem generator
dist/- Compiled JavaScript files (generated by TypeScript compiler)- Includes
.js,.d.ts(type definitions), and.map(source maps) files
- Includes
The library is written in TypeScript and includes full type definitions:
import { UnixShell } from 'unix-shell-js';
import { createExampleFiles } from 'unix-shell-js/dist/example-files';
const shell = new UnixShell({
username: 'user',
fileSystem: createExampleFiles('user'),
persistence: {
enabled: true,
prefix: 'myapp'
}
});
const output: string = shell.execute('ls -la');
console.log(output);Type definitions included:
UnixShellOptions- Constructor optionsFileSystem- Filesystem structure typesPersistenceOptions- Persistence configurationCommandHandler- Custom command function signatureCompletionResult- Tab completion result type
Include the library files in your HTML:
<!DOCTYPE html>
<html>
<head>
<title>Terminal</title>
</head>
<body>
<script src="node_modules/unix-shell-js/dist/index.js"></script>
<script src="node_modules/unix-shell-js/dist/vi-editor.js"></script>
<script src="node_modules/unix-shell-js/dist/example-files.js"></script>
<script>
// Create the shell with example files
const shell = new UnixShell({
username: 'user',
fileSystem: createExampleFiles('user')
});
// Execute a command
const output = shell.execute('ls -la');
console.log(output);
</script>
</body>
</html>const customFS = {
'/': {
'home': {
'myuser': {
'welcome.txt': 'Hello, world!\n',
'projects': {
'app.js': 'console.log("Hello");\n'
}
}
}
}
};
const shell = new UnixShell({
username: 'myuser',
fileSystem: customFS
});The library includes built-in localStorage persistence to automatically save and restore the filesystem, current path, and current user across page reloads:
const shell = new UnixShell({
username: 'user',
fileSystem: createExampleFiles('user'),
persistence: {
enabled: true,
prefix: 'myapp' // Uses 'myapp_filesystem', 'myapp_current_user', 'myapp_current_path'
}
});How it works:
- When persistence is enabled, the shell automatically loads saved state from localStorage on initialization
- After each command execution, the filesystem and current state are automatically saved
- If no saved data exists, it uses the provided
fileSystemandusernameoptions - Use a custom
prefixto avoid conflicts with other apps on the same domain
Clear saved data:
// Clear localStorage for this shell
shell.clearStorage();const customCommands = {
// Example: ps aux command
ps: function(args) {
// Parse flags
let showAll = false;
for (const arg of args) {
if (arg === 'aux' || arg === '-aux') {
showAll = true;
}
}
const processes = [
{ pid: 1, user: 'root', command: '/sbin/init' },
{ pid: 100, user: this.currentUser, command: '-bash' }
];
if (showAll) {
processes.push(
{ pid: 50, user: 'root', command: '/usr/sbin/sshd' },
{ pid: 75, user: 'www-data', command: 'nginx' }
);
}
let output = 'USER PID COMMAND\n';
processes.forEach(p => {
output += `${p.user.padEnd(10)} ${String(p.pid).padStart(4)} ${p.command}\n`;
});
return output;
},
// Example: custom greeting command
hello: function(args) {
const name = args[0] || 'World';
return `Hello, ${name}!`;
}
};
const shell = new UnixShell({
username: 'user',
fileSystem: createExampleFiles('user'),
customCommands: customCommands
});
// Now you can use your custom commands
console.log(shell.execute('hello Alice')); // Output: Hello, Alice!
console.log(shell.execute('ps aux')); // Shows process list// Initialize the shell
const shell = new UnixShell({
username: 'developer',
fileSystem: createExampleFiles('developer'),
customCommands: {
status: function(args) {
// Example custom command
return 'System Status: OK\nUptime: 5 days\nLoad: 0.5';
}
}
});
// Handle user input
function handleCommand(inputText) {
const output = shell.execute(inputText);
// Handle special outputs
if (output === '__CLEAR__') {
// Clear the terminal display
clearTerminal();
} else if (output === '__VI_OPENED__') {
// Vi editor was opened
} else if (output && output.startsWith('__USER_SWITCHED__:')) {
// User changed (su/sudo command)
updatePrompt();
} else {
// Display normal output
displayOutput(output);
}
}When building a terminal UI, you'll need to display a prompt that shows the current user and directory. The prompt typically needs to update after commands like cd or su that change the current path or user.
Pattern for updating the prompt:
function updatePrompt() {
const user = shell.getCurrentUser();
let path = shell.getCurrentPath();
const home = shell.environment.HOME;
// Replace home directory with ~
if (path === home) {
path = '~';
} else if (path.startsWith(home + '/')) {
path = '~' + path.substring(home.length);
}
// Use # for root, $ for regular users
const promptChar = user === 'root' ? '#' : '$';
// Update your prompt element
promptElement.textContent = `${user}@hostname:${path}${promptChar}`;
}Typical command execution flow:
- User enters a command
- Capture the current prompt text (for display in command history)
- Execute the command:
const output = shell.execute(command) - Display the command with its original prompt in history
- Display the command output
- Update the active prompt to reflect any changes (new path, new user, etc.)
- Clear the input field for the next command
Key point: When displaying command history, preserve the prompt as it was when the command was entered. Only update the active input prompt after command execution.
See the live demo source code for a complete working example.
new UnixShell(options)Options:
fileSystem(Object): Custom filesystem structureusername(String): Current user name (default: 'user')customCommands(Object): Custom command handlerspersistence(Object): localStorage persistence configurationenabled(Boolean): Enable/disable persistenceprefix(String): localStorage key prefix (default: 'unixshell')
execute(commandLine)- Execute a command and return outputgetCurrentPath()- Get current working directorygetCurrentUser()- Get current usergetNode(path)- Get filesystem node at pathresolvePath(path)- Resolve relative/absolute pathgetCompletions(partial)- Get tab completion suggestionssaveToStorage()- Manually save state to localStorage (auto-called after commands if persistence enabled)loadFromStorage()- Load state from localStorage (auto-called during initialization if persistence enabled)clearStorage()- Clear saved state from localStorage
help- Show available commandsls- List directory contentscd- Change directorypwd- Print working directorycat- Display file contentsecho- Display textclear- Clear terminalwhoami- Print current userdate- Display date/timeuname- Print system informationenv- Print environment variableshistory- Show command historymkdir- Create directorytouch- Create filerm- Remove file/directorytree- Display directory treeps- Report process status (basic - can be overridden)vi/vim- Edit filesu- Switch usersudo- Execute as superuserexit- Exit user session
Note: All built-in commands can be overridden by providing a custom command with the same name in the customCommands option.
The library includes a fully functional vi/vim modal editor with:
- Normal, Insert, and Command modes
- Movement keys (hjkl, arrows, 0, $, G)
- Insert commands (i, a, o, O)
- Delete commands (x, dd, dw, d$, etc.)
- Yank and paste (Y, p)
- Save and quit (:w, :q, :wq, :q!)
MIT