{"id":32513151,"url":"https://github.com/hypexr/unix-shell-js","last_synced_at":"2026-01-20T17:35:50.552Z","repository":{"id":320338861,"uuid":"1081697121","full_name":"hypexr/unix-shell-js","owner":"hypexr","description":"Browser-based Unix/Linux command emulator with vi editor support","archived":false,"fork":false,"pushed_at":"2025-10-23T07:28:23.000Z","size":23,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-23T09:10:26.115Z","etag":null,"topics":["bash","browser","cli","command-line","emulator","filesystem","javascript","shell","terminal","unix","vi-editor","vim"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hypexr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-23T06:48:03.000Z","updated_at":"2025-10-23T07:28:27.000Z","dependencies_parsed_at":"2025-10-23T09:10:35.645Z","dependency_job_id":"6e3f83b6-22e3-45f4-929e-64ab2df2dc23","html_url":"https://github.com/hypexr/unix-shell-js","commit_stats":null,"previous_names":["hypexr/unix-shell-js"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/hypexr/unix-shell-js","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypexr%2Funix-shell-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypexr%2Funix-shell-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypexr%2Funix-shell-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypexr%2Funix-shell-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hypexr","download_url":"https://codeload.github.com/hypexr/unix-shell-js/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypexr%2Funix-shell-js/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281355341,"owners_count":26486896,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-27T02:00:05.855Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","browser","cli","command-line","emulator","filesystem","javascript","shell","terminal","unix","vi-editor","vim"],"created_at":"2025-10-27T22:50:04.529Z","updated_at":"2025-10-27T22:50:28.315Z","avatar_url":"https://github.com/hypexr.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Unix Shell JS\n\n[![Tests](https://github.com/hypexr/unix-shell-js/actions/workflows/test.yml/badge.svg)](https://github.com/hypexr/unix-shell-js/actions/workflows/test.yml)\n[![Build](https://github.com/hypexr/unix-shell-js/actions/workflows/build.yml/badge.svg)](https://github.com/hypexr/unix-shell-js/actions/workflows/build.yml)\n[![npm version](https://badge.fury.io/js/unix-shell-js.svg)](https://www.npmjs.com/package/unix-shell-js)\n\nA browser-based Unix/Linux command emulator with vi editor support.\n\n**[Try the Live Demo](https://hypexr.github.io/unix-shell-js/)**\n\n## Features\n\n- Common Unix commands (ls, cd, cat, mkdir, rm, etc.)\n- Add and modify commands\n- Customizable filesystem\n- Vi/Vim editor with modal editing\n- Tab completion\n- Command history\n- Pipe and redirection support\n- Wildcard expansion (`*` and `?`)\n- Custom command support\n\n## Installation\n\n### From npm\n\n```bash\nnpm install unix-shell-js\n```\n\n### Local Development\n\nIf you're working locally and want to use this library in another project:\n\n```bash\ncd ../unix-shell-js\nnpm install\nnpm run build\nnpm link\n\ncd ../your-project\nnpm link unix-shell-js\n```\n\n## Development\n\n### Build Commands\n\n- `npm run build` - Compile TypeScript to JavaScript (outputs to `dist/`) and copy to demo\n- `npm run copy-to-demo` - Copy built files to `docs/` directory for GitHub Pages demo\n- `npm run watch` - Watch mode for development (auto-recompiles on changes)\n- `npm run prepublishOnly` - Automatically runs before publishing to npm\n\n### Testing\n\n- `npm test` - Run all tests\n- `npm run test:watch` - Run tests in watch mode\n- `npm run test:coverage` - Run tests with coverage report\n\n### Project Structure\n\n- `src/` - TypeScript source files\n  - `index.ts` - Main Unix Shell implementation\n  - `vi-editor.ts` - Vi/Vim editor\n  - `example-files.ts` - Example filesystem generator\n- `dist/` - Compiled JavaScript files (generated by TypeScript compiler)\n  - Includes `.js`, `.d.ts` (type definitions), and `.map` (source maps) files\n\n## Usage\n\n### TypeScript\n\nThe library is written in TypeScript and includes full type definitions:\n\n```typescript\nimport { UnixShell } from 'unix-shell-js';\nimport { createExampleFiles } from 'unix-shell-js/dist/example-files';\n\nconst shell = new UnixShell({\n    username: 'user',\n    fileSystem: createExampleFiles('user'),\n    persistence: {\n        enabled: true,\n        prefix: 'myapp'\n    }\n});\n\nconst output: string = shell.execute('ls -la');\nconsole.log(output);\n```\n\n**Type definitions included:**\n- `UnixShellOptions` - Constructor options\n- `FileSystem` - Filesystem structure types\n- `PersistenceOptions` - Persistence configuration\n- `CommandHandler` - Custom command function signature\n- `CompletionResult` - Tab completion result type\n\n### JavaScript (Browser)\n\nInclude the library files in your HTML:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003eTerminal\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003cscript src=\"node_modules/unix-shell-js/dist/index.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"node_modules/unix-shell-js/dist/vi-editor.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"node_modules/unix-shell-js/dist/example-files.js\"\u003e\u003c/script\u003e\n    \u003cscript\u003e\n        // Create the shell with example files\n        const shell = new UnixShell({\n            username: 'user',\n            fileSystem: createExampleFiles('user')\n        });\n\n        // Execute a command\n        const output = shell.execute('ls -la');\n        console.log(output);\n    \u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n### Initialize with Custom Filesystem\n\n```javascript\nconst customFS = {\n    '/': {\n        'home': {\n            'myuser': {\n                'welcome.txt': 'Hello, world!\\n',\n                'projects': {\n                    'app.js': 'console.log(\"Hello\");\\n'\n                }\n            }\n        }\n    }\n};\n\nconst shell = new UnixShell({\n    username: 'myuser',\n    fileSystem: customFS\n});\n```\n\n### Enable localStorage Persistence\n\nThe library includes built-in localStorage persistence to automatically save and restore the filesystem, current path, and current user across page reloads:\n\n```javascript\nconst shell = new UnixShell({\n    username: 'user',\n    fileSystem: createExampleFiles('user'),\n    persistence: {\n        enabled: true,\n        prefix: 'myapp'  // Uses 'myapp_filesystem', 'myapp_current_user', 'myapp_current_path'\n    }\n});\n```\n\n**How it works:**\n- When persistence is enabled, the shell automatically loads saved state from localStorage on initialization\n- After each command execution, the filesystem and current state are automatically saved\n- If no saved data exists, it uses the provided `fileSystem` and `username` options\n- Use a custom `prefix` to avoid conflicts with other apps on the same domain\n\n**Clear saved data:**\n```javascript\n// Clear localStorage for this shell\nshell.clearStorage();\n```\n\n### Initialize with Custom Commands\n\n```javascript\nconst customCommands = {\n    // Example: ps aux command\n    ps: function(args) {\n        // Parse flags\n        let showAll = false;\n\n        for (const arg of args) {\n            if (arg === 'aux' || arg === '-aux') {\n                showAll = true;\n            }\n        }\n\n        const processes = [\n            { pid: 1, user: 'root', command: '/sbin/init' },\n            { pid: 100, user: this.currentUser, command: '-bash' }\n        ];\n\n        if (showAll) {\n            processes.push(\n                { pid: 50, user: 'root', command: '/usr/sbin/sshd' },\n                { pid: 75, user: 'www-data', command: 'nginx' }\n            );\n        }\n\n        let output = 'USER       PID COMMAND\\n';\n        processes.forEach(p =\u003e {\n            output += `${p.user.padEnd(10)} ${String(p.pid).padStart(4)} ${p.command}\\n`;\n        });\n\n        return output;\n    },\n\n    // Example: custom greeting command\n    hello: function(args) {\n        const name = args[0] || 'World';\n        return `Hello, ${name}!`;\n    }\n};\n\nconst shell = new UnixShell({\n    username: 'user',\n    fileSystem: createExampleFiles('user'),\n    customCommands: customCommands\n});\n\n// Now you can use your custom commands\nconsole.log(shell.execute('hello Alice')); // Output: Hello, Alice!\nconsole.log(shell.execute('ps aux'));      // Shows process list\n```\n\n### Full Example with Terminal UI\n\n```javascript\n// Initialize the shell\nconst shell = new UnixShell({\n    username: 'developer',\n    fileSystem: createExampleFiles('developer'),\n    customCommands: {\n        status: function(args) {\n            // Example custom command\n            return 'System Status: OK\\nUptime: 5 days\\nLoad: 0.5';\n        }\n    }\n});\n\n// Handle user input\nfunction handleCommand(inputText) {\n    const output = shell.execute(inputText);\n\n    // Handle special outputs\n    if (output === '__CLEAR__') {\n        // Clear the terminal display\n        clearTerminal();\n    } else if (output === '__VI_OPENED__') {\n        // Vi editor was opened\n    } else if (output \u0026\u0026 output.startsWith('__USER_SWITCHED__:')) {\n        // User changed (su/sudo command)\n        updatePrompt();\n    } else {\n        // Display normal output\n        displayOutput(output);\n    }\n}\n```\n\n## Integration Tips\n\n### Managing the Command Prompt\n\nWhen 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.\n\n**Pattern for updating the prompt:**\n\n```javascript\nfunction updatePrompt() {\n    const user = shell.getCurrentUser();\n    let path = shell.getCurrentPath();\n    const home = shell.environment.HOME;\n\n    // Replace home directory with ~\n    if (path === home) {\n        path = '~';\n    } else if (path.startsWith(home + '/')) {\n        path = '~' + path.substring(home.length);\n    }\n\n    // Use # for root, $ for regular users\n    const promptChar = user === 'root' ? '#' : '$';\n\n    // Update your prompt element\n    promptElement.textContent = `${user}@hostname:${path}${promptChar}`;\n}\n```\n\n**Typical command execution flow:**\n\n1. User enters a command\n2. Capture the current prompt text (for display in command history)\n3. Execute the command: `const output = shell.execute(command)`\n4. Display the command with its original prompt in history\n5. Display the command output\n6. Update the active prompt to reflect any changes (new path, new user, etc.)\n7. Clear the input field for the next command\n\n**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.\n\nSee the [live demo source code](https://github.com/hypexr/unix-shell-js/blob/main/docs/index.html) for a complete working example.\n\n## API Reference\n\n### UnixShell Constructor\n\n```javascript\nnew UnixShell(options)\n```\n\n**Options:**\n- `fileSystem` (Object): Custom filesystem structure\n- `username` (String): Current user name (default: 'user')\n- `customCommands` (Object): Custom command handlers\n- `persistence` (Object): localStorage persistence configuration\n  - `enabled` (Boolean): Enable/disable persistence\n  - `prefix` (String): localStorage key prefix (default: 'unixshell')\n\n### Methods\n\n- `execute(commandLine)` - Execute a command and return output\n- `getCurrentPath()` - Get current working directory\n- `getCurrentUser()` - Get current user\n- `getNode(path)` - Get filesystem node at path\n- `resolvePath(path)` - Resolve relative/absolute path\n- `getCompletions(partial)` - Get tab completion suggestions\n- `saveToStorage()` - Manually save state to localStorage (auto-called after commands if persistence enabled)\n- `loadFromStorage()` - Load state from localStorage (auto-called during initialization if persistence enabled)\n- `clearStorage()` - Clear saved state from localStorage\n\n### Built-in Commands\n\n- `help` - Show available commands\n- `ls` - List directory contents\n- `cd` - Change directory\n- `pwd` - Print working directory\n- `cat` - Display file contents\n- `echo` - Display text\n- `clear` - Clear terminal\n- `whoami` - Print current user\n- `date` - Display date/time\n- `uname` - Print system information\n- `env` - Print environment variables\n- `history` - Show command history\n- `mkdir` - Create directory\n- `touch` - Create file\n- `rm` - Remove file/directory\n- `tree` - Display directory tree\n- `ps` - Report process status (basic - can be overridden)\n- `vi/vim` - Edit file\n- `su` - Switch user\n- `sudo` - Execute as superuser\n- `exit` - Exit user session\n\n**Note:** All built-in commands can be overridden by providing a custom command with the same name in the `customCommands` option.\n\n## Vi Editor\n\nThe library includes a fully functional vi/vim modal editor with:\n\n- Normal, Insert, and Command modes\n- Movement keys (hjkl, arrows, 0, $, G)\n- Insert commands (i, a, o, O)\n- Delete commands (x, dd, dw, d$, etc.)\n- Yank and paste (Y, p)\n- Save and quit (:w, :q, :wq, :q!)\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhypexr%2Funix-shell-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhypexr%2Funix-shell-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhypexr%2Funix-shell-js/lists"}