terminal
The terminal module provides comprehensive command-line interface capabilities for CodeboltJS. It enables execution of shell commands, real-time output streaming, and process management for development automation tasks.
- eventEmitter - EventEmitter for terminal events and real-time output handling.
- executeCommand - Executes a given command in the terminal and returns the result. Listens for WebSocket messages indicating output, error, or finish state and resolves the promise accordingly.
- executeCommandRunUntilError - Executes a command and keeps running until an error occurs. Useful for continuous processes that should stop on first failure.
- executeCommandWithStream - Executes a command and streams output in real-time via EventEmitter. Ideal for long-running commands where you need to monitor output as it happens.
- sendManualInterrupt - Sends a manual interrupt signal (Ctrl+C) to stop a running command or process in the terminal.
Key Features
Command Execution
- Basic Execution: Run shell commands with
executeCommand() - Stream Execution: Monitor real-time output with
executeCommandWithStream() - Error-Based Execution: Run commands until error with
executeCommandRunUntilError() - Process Control: Interrupt running commands with
sendManualInterrupt()
Output Handling
- Standard Output: Capture command stdout for processing
- Error Output: Handle stderr for error diagnostics
- Exit Codes: Check command execution status
- Real-Time Streaming: Monitor output as it's generated
Quick Start Guide
Basic Command Execution
import codebolt from '@codebolt/codeboltjs';
// Execute a simple command
const result = await codebolt.terminal.executeCommand('echo "Hello, World!"');
console.log('✅ Command output:', result.stdout);
// Check Node.js version
const nodeVersion = await codebolt.terminal.executeCommand('node --version');
console.log('Node version:', nodeVersion.stdout);
// List directory contents
const dirListing = await codebolt.terminal.executeCommand('ls -la');
console.log('Directory contents:', dirListing.stdout);
Command with Error Handling
// Execute command with proper error handling
try {
const result = await codebolt.terminal.executeCommand('npm install');
if (result.type === 'commandFinish') {
console.log('✅ Installation successful');
console.log('Exit code:', result.exitCode);
} else if (result.type === 'commandError') {
console.error('❌ Installation failed:', result.error);
console.error('Error details:', result.stderr);
}
} catch (error) {
console.error('❌ Command execution error:', error.message);
}
Streaming Command Output
// Execute command with real-time output streaming
const streamEmitter = codebolt.terminal.executeCommandWithStream('npm run build');
streamEmitter.on('commandOutput', (data) => {
console.log('📡 Build output:', data.output);
});
streamEmitter.on('commandError', (error) => {
console.error('❌ Build error:', error.error);
});
streamEmitter.on('commandFinish', (finish) => {
console.log('✅ Build completed');
console.log('Exit code:', finish.exitCode);
});
Common Workflows
Package Management Workflow
// Check package.json exists
const checkResult = await codebolt.terminal.executeCommand('test -f package.json');
if (checkResult.exitCode === 0) {
console.log('📦 package.json found');
// Install dependencies
const installResult = await codebolt.terminal.executeCommand('npm install');
if (installResult.type === 'commandFinish') {
console.log('✅ Dependencies installed');
}
}
Git Operations Workflow
// Check Git status
const gitStatus = await codebolt.terminal.executeCommand('git status --porcelain');
if (gitStatus.stdout.trim()) {
console.log('📝 Repository has changes');
// Stage and commit
await codebolt.terminal.executeCommand('git add .');
await codebolt.terminal.executeCommand('git commit -m "Update files"');
} else {
console.log('✨ Repository is clean');
}
Build Process Workflow
// Run build with streaming output
const buildEmitter = codebolt.terminal.executeCommandWithStream('npm run build');
let buildProgress = 0;
buildEmitter.on('commandOutput', (data) => {
console.log(data.output);
// Parse build progress
const progressMatch = data.output.match(/(\d+)%/);
if (progressMatch) {
buildProgress = parseInt(progressMatch[1]);
console.log(`📊 Build progress: ${buildProgress}%`);
}
});
buildEmitter.on('commandFinish', (finish) => {
if (finish.exitCode === 0) {
console.log('✅ Build successful');
} else {
console.error('❌ Build failed');
}
});
Testing Workflow
// Run tests with real-time output
const testEmitter = codebolt.terminal.executeCommandWithStream('npm test');
let testCount = 0;
let passCount = 0;
let failCount = 0;
testEmitter.on('commandOutput', (data) => {
const output = data.output;
// Track test results
if (output.includes('✓') || output.includes('pass')) {
passCount++;
console.log(`✅ Test passed: ${passCount}`);
} else if (output.includes('✗') || output.includes('fail')) {
failCount++;
console.log(`❌ Test failed: ${failCount}`);
}
testCount++;
});
testEmitter.on('commandFinish', (finish) => {
console.log(`\n📊 Test Summary:`);
console.log(` Total: ${testCount}`);
console.log(` ✅ Passed: ${passCount}`);
console.log(` ❌ Failed: ${failCount}`);
});
Module Integration Examples
Integration with File System Module
// Create directory structure via terminal
await codebolt.terminal.executeCommand('mkdir -p src/components src/utils');
// Verify creation
const files = await codebolt.fs.listFile('./src');
console.log('Created directories:', files);
// Create file and verify
await codebolt.fs.createFile('index.js', 'console.log("Hello");', './src');
const checkFile = await codebolt.terminal.executeCommand('test -f src/index.js && echo "File exists"');
console.log(checkFile.stdout);
Integration with Git Module
// Initialize repository via terminal
await codebolt.terminal.executeCommand('git init');
// Create .gitignore file
await codebolt.fs.createFile('.gitignore', 'node_modules/\n.env', '.');
// Stage and commit
await codebolt.git.addAll();
await codebolt.git.commit('Initial commit');
// Verify with git log
const gitLog = await codebolt.terminal.executeCommand('git log --oneline');
console.log('Git history:', gitLog.stdout);
Integration with Browser Module
// Start development server
const serverEmitter = codebolt.terminal.executeCommandWithStream('npm start');
let serverReady = false;
serverEmitter.on('commandOutput', (data) => {
console.log(data.output);
// Detect when server is ready
if (data.output.includes('Server running') || data.output.includes('localhost')) {
serverReady = true;
// Open browser to test
setTimeout(async () => {
await codebolt.browser.newPage();
await codebolt.browser.goToPage('http://localhost:3000');
console.log('✅ Browser opened to test server');
}, 1000);
}
});
Advanced Usage Patterns
Command Chaining
// Chain multiple commands
async function chainCommands(commands) {
const results = [];
for (const cmd of commands) {
console.log(`🔄 Executing: ${cmd}`);
const result = await codebolt.terminal.executeCommand(cmd);
if (result.type === 'commandFinish') {
console.log('✅ Success');
results.push({ command: cmd, success: true, result });
} else {
console.error('❌ Failed:', result.error);
results.push({ command: cmd, success: false, error: result.error });
break; // Stop on failure
}
}
return results;
}
// Usage
const commands = [
'mkdir -p build',
'npm run build',
'npm run test'
];
await chainCommands(commands);
Parallel Command Execution
// Execute multiple commands in parallel
async function executeParallel(commands) {
const promises = commands.map(async (cmd) => {
try {
const result = await codebolt.terminal.executeCommand(cmd);
return {
command: cmd,
success: result.type === 'commandFinish',
result
};
} catch (error) {
return {
command: cmd,
success: false,
error: error.message
};
}
});
const results = await Promise.all(promises);
console.log('📊 Parallel execution results:');
results.forEach(({ command, success }) => {
console.log(` ${success ? '✅' : '❌'} ${command}`);
});
return results;
}
// Usage
await executeParallel([
'npm run lint',
'npm run type-check',
'npm run test'
]);
Conditional Command Execution
// Execute commands based on conditions
async function conditionalWorkflow() {
// Check if Node.js is installed
const nodeCheck = await codebolt.terminal.executeCommand('which node');
if (nodeCheck.exitCode !== 0) {
console.error('❌ Node.js not found. Please install Node.js first.');
return;
}
console.log('✅ Node.js found');
// Check if package.json exists
const packageCheck = await codebolt.terminal.executeCommand('test -f package.json');
if (packageCheck.exitCode === 0) {
console.log('📦 package.json found, installing dependencies...');
await codebolt.terminal.executeCommand('npm install');
} else {
console.log('⚠️ No package.json found, initializing project...');
await codebolt.terminal.executeCommand('npm init -y');
}
}
Timeout-Based Command Execution
// Execute command with timeout
async function executeWithTimeout(command, timeoutMs = 30000) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error(`Command timeout after ${timeoutMs}ms`)), timeoutMs);
});
try {
const result = await Promise.race([
codebolt.terminal.executeCommand(command),
timeoutPromise
]);
console.log('✅ Command completed');
return result;
} catch (error) {
console.error('⏰ Command timed out or failed:', error.message);
// Send interrupt to stop the command
await codebolt.terminal.sendManualInterrupt();
throw error;
}
}
// Usage
await executeWithTimeout('npm run build', 60000); // 60 second timeout
Retry Logic for Commands
// Execute command with retry logic
async function executeWithRetry(command, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
console.log(`🔄 Attempt ${attempt}/${maxRetries}: ${command}`);
try {
const result = await codebolt.terminal.executeCommand(command);
if (result.type === 'commandFinish') {
console.log('✅ Command successful');
return result;
} else {
throw new Error(result.error);
}
} catch (error) {
console.error(`❌ Attempt ${attempt} failed:`, error.message);
if (attempt === maxRetries) {
throw new Error(`Command failed after ${maxRetries} attempts`);
}
// Wait before retrying
const waitTime = attempt * 2000; // Exponential backoff
console.log(`⏳ Waiting ${waitTime}ms before retry...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
}
}
// Usage
await executeWithRetry('npm install', 5);
Error Handling
Comprehensive Error Handling
async function safeCommandExecution(command) {
try {
const result = await codebolt.terminal.executeCommand(command);
if (result.type === 'commandFinish') {
if (result.exitCode === 0) {
console.log('✅ Command executed successfully');
return {
success: true,
stdout: result.stdout,
exitCode: result.exitCode
};
} else {
console.warn('⚠️ Command completed with errors');
return {
success: false,
stdout: result.stdout,
stderr: result.stderr,
exitCode: result.exitCode
};
}
} else if (result.type === 'commandError') {
console.error('❌ Command execution failed:', result.error);
throw new Error(result.error);
}
} catch (error) {
console.error('❌ Unexpected error:', error.message);
// Handle specific error types
if (error.message.includes('ENOENT')) {
console.error('💡 Command not found. Check if the command is installed.');
} else if (error.message.includes('EACCES')) {
console.error('💡 Permission denied. Try with sudo or check permissions.');
}
throw error;
}
}
// Usage
await safeCommandExecution('npm run build');
Performance Considerations
Optimizing Command Execution
// Batch commands to reduce overhead
async function batchCommands(commands) {
const batchCommand = commands.join(' && ');
console.log(`🔄 Executing batch: ${batchCommand}`);
const result = await codebolt.terminal.executeCommand(batchCommand);
if (result.exitCode === 0) {
console.log('✅ All commands executed successfully');
} else {
console.error('❌ Batch execution failed');
}
return result;
}
// Usage
await batchCommands([
'mkdir -p build',
'npm run build',
'npm run test'
]);
Parallel vs Sequential Execution
// Choose between parallel and sequential based on dependencies
// ❌ Bad: Sequential for independent commands
await codebolt.terminal.executeCommand('npm run lint');
await codebolt.terminal.executeCommand('npm run type-check');
await codebolt.terminal.executeCommand('npm run test');
// ✅ Good: Parallel for independent commands
await executeParallel([
'npm run lint',
'npm run type-check',
'npm run test'
]);
// ✅ Good: Sequential for dependent commands
await batchCommands([
'npm install',
'npm run build',
'npm run test'
]);
Common Pitfalls and Solutions
Pitfall 1: Not Checking Exit Codes
// ❌ Bad: Assumes command succeeded
await codebolt.terminal.executeCommand('npm install');
console.log('Dependencies installed');
// ✅ Good: Check exit code
const result = await codebolt.terminal.executeCommand('npm install');
if (result.exitCode === 0) {
console.log('✅ Dependencies installed');
} else {
console.error('❌ Installation failed');
}
Pitfall 2: Ignoring Error Output
// ❌ Bad: Only checks stdout
const result = await codebolt.terminal.executeCommand('npm run build');
console.log(result.stdout);
// ✅ Good: Check both stdout and stderr
if (result.stderr) {
console.error('Build errors:', result.stderr);
}
if (result.exitCode !== 0) {
console.error('Build failed with exit code:', result.exitCode);
}
Pitfall 3: Not Handling Long-Running Commands
// ❌ Bad: No timeout for long-running command
await codebolt.terminal.executeCommand('npm run build');
// ✅ Good: Use streaming or timeout
const emitter = codebolt.terminal.executeCommandWithStream('npm run build');
// Or
await executeWithTimeout('npm run build', 60000);
Pitfall 4: Not Cleaning Up Processes
// ❌ Bad: Leaves processes running
const server = codebolt.terminal.executeCommandWithStream('npm start');
// Forget about it...
// ✅ Good: Clean up properly
const server = codebolt.terminal.executeCommandWithStream('npm start');
// Later, when done:
await codebolt.terminal.sendManualInterrupt();
if (server.cleanup) {
server.cleanup();
}
Best Practices
1. Always Check Exit Codes
const result = await codebolt.terminal.executeCommand('npm test');
if (result.exitCode === 0) {
console.log('✅ Tests passed');
} else {
console.error('❌ Tests failed');
}
2. Use Streaming for Long Commands
const emitter = codebolt.terminal.executeCommandWithStream('npm run build');
emitter.on('commandOutput', (data) => {
console.log(data.output);
});
emitter.on('commandFinish', (finish) => {
console.log('✅ Build completed');
});
3. Implement Proper Error Handling
try {
const result = await codebolt.terminal.executeCommand('npm install');
if (result.type === 'commandError') {
throw new Error(result.error);
}
if (result.exitCode !== 0) {
throw new Error(`Command failed with exit code ${result.exitCode}`);
}
} catch (error) {
console.error('Command failed:', error.message);
throw error;
}
4. Clean Up Resources
const emitter = codebolt.terminal.executeCommandWithStream('npm start');
try {
// Do work...
} finally {
await codebolt.terminal.sendManualInterrupt();
if (emitter.cleanup) {
emitter.cleanup();
}
}
5. Use Appropriate Command Type
// Use executeCommand for simple commands
await codebolt.terminal.executeCommand('ls -la');
// Use executeCommandWithStream for long-running commands
const emitter = codebolt.terminal.executeCommandWithStream('npm run build');
// Use executeCommandRunUntilError for continuous monitoring
await codebolt.terminal.executeCommandRunUntilError('npm run watch');
Troubleshooting
Common Issues and Solutions
Issue: Command not found
- Solution: Verify the command is installed and in PATH
Issue: Permission denied
- Solution: Check file permissions or use appropriate sudo privileges
Issue: Command hangs indefinitely
- Solution: Implement timeouts and use
sendManualInterrupt()
Issue: Output not captured
- Solution: Check if command outputs to stderr instead of stdout
Issue: Exit code always 0
- Solution: Some commands don't set proper exit codes; check output for errors