Skip to content

Zurard/WebShell

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

34 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ–₯️ WebShell - Interactive Terminal Emulator

A full-stack web-based file system simulator with a beautiful, interactive terminal interface. Built with TypeScript, Node.js WebSockets, and React with Next.js.


πŸ“‹ Table of Contents


✨ Features

  • Real-time Terminal Interface: Interactive terminal with cursor support
  • Virtual File System: Create, manage, and navigate files and directories
  • WebSocket Communication: Real-time bidirectional communication between frontend and backend
  • Beautifully Formatted Output:
    • List formatting with item counts
    • Path highlighting
    • Success/error indicators
    • JSON and table displays
  • Command History: Persistent command history across sessions
  • Responsive Design: Works on desktop and tablet
  • Modern UI: Dark terminal theme with color-coded responses

πŸ“ Project Structure

webshell-monorepo/
β”œβ”€β”€ packages/
β”‚   β”œβ”€β”€ backend/              # Node.js WebSocket server
β”‚   β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”‚   β”œβ”€β”€ index.ts      # WebSocket server entry point
β”‚   β”‚   β”‚   └── shell/
β”‚   β”‚   β”‚       β”œβ”€β”€ executor.ts    # Command execution logic
β”‚   β”‚   β”‚       β”œβ”€β”€ parser.ts      # Command parsing
β”‚   β”‚   β”‚       β”œβ”€β”€ registry.ts    # Command handlers
β”‚   β”‚   β”‚       └── state.ts       # Virtual file system state
β”‚   β”‚   β”œβ”€β”€ package.json
β”‚   β”‚   └── tsconfig.json
β”‚   β”‚
β”‚   β”œβ”€β”€ frontend/             # Next.js React application
β”‚   β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ page.tsx
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ layout.tsx
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ globals.css
β”‚   β”‚   β”‚   β”‚   └── components/
β”‚   β”‚   β”‚   β”‚       └── terminal.tsx    # Main terminal component
β”‚   β”‚   β”‚   └── hooks/
β”‚   β”‚   β”‚       └── webSocket.ts        # WebSocket hook
β”‚   β”‚   β”œβ”€β”€ package.json
β”‚   β”‚   β”œβ”€β”€ tsconfig.json
β”‚   β”‚   └── next.config.ts
β”‚   β”‚
β”‚   └── shared/               # Shared type definitions
β”‚       β”œβ”€β”€ src/
β”‚       β”‚   β”œβ”€β”€ index.ts
β”‚       β”‚   └── types.ts      # Shared TypeScript types
β”‚       β”œβ”€β”€ package.json
β”‚       └── tsconfig.json
β”‚
β”œβ”€β”€ package.json              # Root workspace config
└── README.md                 # This file

πŸ› οΈ Tech Stack

Backend

  • Node.js - Runtime environment
  • TypeScript - Type-safe JavaScript
  • ws (WebSockets) - Real-time bidirectional communication
  • npm workspaces - Monorepo management

Frontend

  • React 18 - UI library
  • Next.js - React framework with SSR
  • TypeScript - Type safety
  • Tailwind CSS - Utility-first CSS framework

Shared

  • TypeScript Types - Centralized type definitions for backend & frontend

πŸ“¦ Prerequisites

Before you begin, ensure you have installed:

  • Node.js v18 or higher (Download)
  • npm v9 or higher (comes with Node.js)

Check your versions:

node --version
npm --version

βš™οΈ Installation

1. Clone the Repository

git clone <repository-url>
cd terminal

2. Install Dependencies

Install root-level dependencies and all workspace packages:

npm install

This will automatically install dependencies for:

  • packages/backend
  • packages/frontend
  • packages/shared

3. Verify Installation

Check that all packages are installed:

npm list --depth=0

πŸ”§ Setup & Configuration

Backend Configuration

The backend server runs on port 8080 by default. To change it:

  1. Open packages/backend/src/index.ts
  2. Modify the PORT variable:
const PORT = 8080; // Change this value

Frontend Configuration

The frontend connects to the WebSocket server at ws://localhost:8080. To change it:

  1. Open packages/frontend/src/app/hooks/webSocket.ts
  2. Modify the WebSocket URL:
const { command, isConnected, sendCommand } = useWebSocket('ws://localhost:8080');

πŸš€ Running the Project

Option 1: Run Everything (Recommended)

Start both frontend and backend simultaneously:

npm run dev

This command:

  • Starts the backend on ws://localhost:8080
  • Starts the frontend on http://localhost:3000

Option 2: Run Backend Only

npm run dev:backend

The backend will be available at ws://localhost:8080

Option 3: Run Frontend Only

npm run dev:frontend

The frontend will be available at http://localhost:3000 (requires backend running separately)

Build for Production

Build all packages:

npm run build

Build specific packages:

npm run build:frontend
npm run build:backend

πŸ“ Available Commands

The terminal supports the following commands:

File System Navigation

Command Syntax Description
scan scan List all files and directories in current directory
warp warp <directory> Change to a different directory
pwd pwd Print current working directory path

Directory Operations

Command Syntax Description
forge forge <dirname> Create a new directory
murderdir murderdir <dirname> Remove a directory

File Operations

Command Syntax Description
spawn spawn <filename> Create a new file
inject inject <filename> <content> Write content to a file
read read <filename> Display file contents
murder murder <filename> Delete a file

Utility Commands

Command Syntax Description
help help Show all available commands
clear clear Clear terminal history

Example Usage

# Navigate file system
forge myproject
warp myproject
pwd

# Create and edit files
spawn README.md
inject README.md "Hello World"
read README.md

# List contents
scan

# Go back
warp ..

# Get help
help

πŸ”„ How It Works

Communication Flow

User Input (Frontend)
    ↓
Terminal Component (React)
    ↓
WebSocket Send (Hook)
    ↓
Backend Server (WebSocket)
    ↓
Command Parser β†’ Command Registry β†’ Handler
    ↓
Execute on Virtual FS (State)
    ↓
Format Output (Executor)
    ↓
WebSocket Response
    ↓
OutputRenderer Component
    ↓
Display to User (Pretty Formatted)

Step-by-Step Process

1. User Input

User types a command in the terminal and presses Enter.

2. Frontend Processing

  • Input captured by hidden textarea in terminal.tsx
  • Command added to history display
  • Sent to backend via WebSocket

3. Backend Parsing

parser.ts tokenizes the command:

"spawn hello.txt" β†’ { cmd: "spawn", args: ["hello.txt"] }

4. Command Execution

registry.ts looks up the handler function for the command and executes it with current state.

5. Format Output

executor.ts formats the raw output into structured data:

{
  format: "list",           // Type of format
  content: ["file1", "file2"],  // Actual content
  metadata: { itemCount: 2 }    // Additional info
}

6. State Management

state.ts maintains the virtual file system tree with file and directory nodes.

7. Response to Frontend

Backend sends structured response:

{
  "type": "output",
  "data": "...",
  "structured": {
    "format": "list",
    "content": [...],
    "metadata": {...}
  },
  "timestamp": 1234567890
}

8. Frontend Rendering

OutputRenderer component interprets format and renders beautifully:

  • list β†’ Formatted with arrows (β†’)
  • path β†’ Blue highlighted box
  • success β†’ Green checkmark (βœ“)
  • error β†’ Red X (βœ—)
  • table β†’ Bordered table
  • json β†’ Code block with syntax

πŸ—οΈ Architecture

Type System

All types are defined in packages/shared/src/types.ts:

// Command input from frontend
type CommandMessage = {
  command: string;
  timestamp: number;
};

// Structured output format
type StructuredOutput = {
  format: OutputFormat;  // "text" | "list" | "table" | "json" | "path" | "success" | "error"
  content: string | string[] | Record<string, string>;
  metadata?: {
    itemCount?: number;
    isEmpty?: boolean;
  };
};

// Response from backend
type CommandResponse = {
  type: "output" | "error" | "clear";
  data?: string;
  structured?: StructuredOutput;
  timestamp: number;
};

Virtual File System

Files and directories are represented as nodes:

type FileNode = {
  id: string;                    // Unique identifier
  name: string;                  // File/directory name
  type: "file" | "directory";
  parent: FileNode | null;       // Parent directory
  children?: FileNode[];         // For directories only
  content?: string;              // For files only
};

State Management

Backend maintains state per connection:

type ShellState = {
  cwd: FileNode;           // Current working directory
  history: string[];       // Command history
};

πŸ’» Development

Project Scripts

Script Purpose
npm run dev Start both backend and frontend in dev mode
npm run dev:backend Start only backend dev server
npm run dev:frontend Start only frontend dev server
npm run build Build all packages for production
npm run build:backend Build backend only
npm run build:frontend Build frontend only

Adding New Commands

To add a new command:

  1. Create Handler in packages/backend/src/shell/registry.ts:
export const myCommandHandler: CommandHandler = (args, state) => {
  // Command logic here
  return "Output message";
};
  1. Register Command in commandRegistry:
export const commandRegistry: Record<string, CommandHandler> = {
  mycommand: myCommandHandler,
  // ... other commands
};
  1. Add Format Logic in packages/backend/src/shell/executor.ts:
} else if (cmdName === "mycommand") {
  // Format output as desired
  structured = { format: "list", content: [...] };
}
  1. Test by running and trying the command:
npm run dev
# Terminal: mycommand

Debugging

Enable console logs in:


πŸ› Troubleshooting

Frontend can't connect to backend

Problem: "WebSocket is not connected" in browser console

Solutions:

  1. Ensure backend is running: npm run dev:backend
  2. Check WebSocket URL in webSocket.ts
  3. Verify backend port matches (default 8080)
  4. Check browser console for CORS errors

Commands not found

Problem: "Command not found" error

Solutions:

  1. Check command spelling (case-sensitive)
  2. Verify command is registered in commandRegistry
  3. Check handler function exists and is exported
  4. Restart both frontend and backend

Port already in use

Problem: Error: listen EADDRINUSE

Solutions:

  1. Find process using port: lsof -i :8080
  2. Kill process: kill -9 <PID>
  3. Or change PORT in index.ts


Built with ❀️ using TypeScript, Node.js, and React

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors