Overview
The Shell class provides an interactive bash-like shell with full command execution, pipes, redirects, line editing, history, tab completion, and job control. It can operate in both visual mode (attached to a terminal) and headless mode (programmatic execution).
Creating a Shell
import { Shell , Kernel , createDefaultRegistry } from '@lifo-sh/core' ;
import { Terminal } from '@xterm/xterm' ;
const kernel = new Kernel ();
await kernel . boot ();
const registry = createDefaultRegistry ();
const terminal = new Terminal ();
terminal . open ( document . getElementById ( 'terminal' ));
const env = kernel . getDefaultEnv ();
const shell = new Shell ( terminal , kernel . vfs , registry , env );
shell . start ();
Constructor
constructor (
terminal : ITerminal ,
vfs : VFS ,
registry : CommandRegistry ,
env : Record < string , string >
)
Terminal instance for input/output. Can be a visual terminal (xterm.js) or headless terminal.
Virtual filesystem instance
Command registry for resolving commands
env
Record<string, string>
required
Initial environment variables
Instance Methods
execute()
Programmatic command execution with captured stdout/stderr. Used for headless mode.
async execute (
cmd : string ,
options ?: ExecuteOptions
): Promise < { stdout : string ; stderr : string ; exitCode : number } >
Shell command to execute. Supports pipes, redirects, variables, etc.
Working directory for this command
Additional environment variables (merged with shell env)
Streaming stdout callback
Streaming stderr callback
Example:
const result = await shell . execute ( 'ls -la /home/user' );
console . log ( result . stdout );
console . log ( 'Exit code:' , result . exitCode );
// With pipes
const result = await shell . execute ( 'ls | grep .txt | wc -l' );
console . log ( 'Text files:' , result . stdout . trim ());
// With redirects
await shell . execute ( 'echo "Hello" > /tmp/output.txt' );
// With streaming
await shell . execute ( 'npm install' , {
cwd: '/home/user/project' ,
onStdout : ( data ) => console . log ( 'OUT:' , data ),
onStderr : ( data ) => console . error ( 'ERR:' , data )
});
// With stdin
const result = await shell . execute ( 'grep foo' , {
stdin: 'foo \n bar \n baz \n '
});
start()
Start the shell in visual mode. Attaches input handlers to the terminal and displays the prompt.
Example:
import { Terminal } from '@xterm/xterm' ;
const terminal = new Terminal ();
terminal . open ( document . getElementById ( 'terminal' ));
const shell = new Shell ( terminal , vfs , registry , env );
shell . start (); // Shell is now interactive
sourceFile()
Source a shell script file, executing its contents in the current shell context.
async sourceFile ( path : string ): Promise < void >
Path to shell script file
Example:
// Create a config file
vfs . writeFile ( '/home/user/.bashrc' , `
export PATH=/custom/bin:$PATH
alias ll='ls -la'
echo "Welcome, $USER!"
` );
// Source it
await shell . sourceFile ( '/home/user/.bashrc' );
// Environment is now updated
console . log ( shell . getEnv (). PATH ); // '/custom/bin:/usr/bin:/bin'
getCwd()
Get current working directory.
Current working directory
Example:
console . log ( shell . getCwd ()); // '/home/user'
setCwd()
Set current working directory.
setCwd ( cwd : string ): void
Example:
shell . setCwd ( '/tmp' );
console . log ( shell . getCwd ()); // '/tmp'
getEnv()
Get current environment variables.
getEnv (): Record < string , string >
Example:
const env = shell . getEnv ();
console . log ( env . HOME ); // '/home/user'
console . log ( env . PATH ); // '/usr/bin:/bin'
getVfs()
Get VFS instance.
Virtual filesystem instance
getRegistry()
Get command registry.
getRegistry (): CommandRegistry
Command registry instance
getJobTable()
Get job control table (for background jobs).
Example:
const jobTable = shell . getJobTable ();
const jobs = jobTable . list ();
for ( const job of jobs ) {
console . log ( `[ ${ job . id } ] ${ job . status } ${ job . command } ` );
}
tokenize()
Tokenize a command line string (legacy, kept for backward compatibility).
tokenize ( input : string ): string []
Command line string to tokenize
Example:
const tokens = shell . tokenize ( 'ls -la "my file.txt"' );
console . log ( tokens ); // ['ls', '-la', 'my file.txt']
Built-in Commands
The shell provides these built-in commands:
Change directory.
cd [directory]
cd ~ # Home directory
cd - # Previous directory
cd .. # Parent directory
pwd
Print working directory.
echo
Print arguments.
echo Hello, World!
echo $HOME
echo "Line 1\nLine 2"
export
Set environment variables.
export PATH = / custom / bin : $PATH
export NODE_ENV = production
clear
Clear the terminal screen.
exit
Exit the shell.
history
Show command history.
jobs
List background jobs.
Bring background job to foreground.
Resume background job.
source / .
Execute commands from a file.
source ~/.bashrc
. /etc/profile
alias
Create command aliases.
alias ll = 'ls -la'
alias gs = 'git status'
alias # List all aliases
unalias
Remove command aliases.
test / [
Evaluate conditional expressions.
test -f /home/user/file.txt && echo "exists"
[ -d /tmp ] && echo "directory exists"
true
Always succeeds (exit code 0).
false
Always fails (exit code 1).
Shell Features
Pipes
Chain commands together:
ls | grep .txt | wc -l
cat file.txt | sort | uniq
Redirects
Redirect input/output:
ls > files.txt # Redirect stdout to file
cat < input.txt # Redirect file to stdin
command 2> errors.txt # Redirect stderr to file
command & > output.txt # Redirect both stdout and stderr
command >> append.txt # Append to file
Background Jobs
Run commands in background:
sleep 10 & # Run in background
jobs # List jobs
fg 1 # Bring job 1 to foreground
Command Chaining
Chain multiple commands:
command1 && command2 # Run command2 if command1 succeeds
command1 || command2 # Run command2 if command1 fails
command1 ; command2 # Run both regardless
Variable Expansion
Expand variables:
echo $HOME
echo ${ USER } _backup
PATH = /custom: $PATH
Command Substitution
Substitute command output:
echo "Today is $( date )"
files = $( ls | wc -l )
Glob Patterns
Filename expansion:
ls * .txt
cat file?.log
rm [abc] * .tmp
Quotes
Control word splitting and expansion:
echo " $HOME expansion" # Double quotes: expand variables
echo '$HOME literal' # Single quotes: no expansion
echo "Line 1\nLine 2" # Escape sequences work
History Expansion
Recall previous commands:
!! # Repeat last command
! 10 # Repeat command 10
! grep # Repeat last command starting with 'grep'
Tab Completion
Press Tab to autocomplete:
Command names
File paths
Directory names
Environment variables
Press Tab twice to show all completions.
Line Editing
Keyboard shortcuts:
Ctrl+A - Move to beginning of line
Ctrl+E - Move to end of line
Ctrl+U - Clear line
Ctrl+C - Cancel current command
Ctrl+D - EOF / exit
Arrow Up/Down - Navigate history
Arrow Left/Right - Move cursor
Home/End - Jump to start/end
Backspace/Delete - Delete characters
Type Definitions
interface ExecuteOptions {
cwd ?: string ;
env ?: Record < string , string >;
onStdout ?: ( data : string ) => void ;
onStderr ?: ( data : string ) => void ;
stdin ?: string ;
}
interface ITerminal {
write ( data : string ) : void ;
onData ( handler : ( data : string ) => void ) : void ;
clear () : void ;
focus () : void ;
}
Source Location
// src/shell/Shell.ts (926 lines)
export class Shell {
constructor (
terminal : ITerminal ,
vfs : VFS ,
registry : CommandRegistry ,
env : Record < string , string >
);
async execute ( cmd : string , options ?: ExecuteOptions ) : Promise <{
stdout : string ;
stderr : string ;
exitCode : number ;
}>;
start () : void ;
async sourceFile ( path : string ) : Promise < void >;
getCwd () : string ;
setCwd ( cwd : string ) : void ;
getEnv () : Record < string , string >;
getVfs () : VFS ;
getRegistry () : CommandRegistry ;
getJobTable () : JobTable ;
tokenize ( input : string ) : string [];
}