Local Environment Setup
The local adapter enables command execution on your local machine with native shell integration, runtime optimization, and comprehensive process management.
Installation
The local adapter is included in the core package:
npm install @xec-sh/core
# or
yarn add @xec-sh/core
Basic Configuration
Default Setup
The local adapter works out of the box with zero configuration:
import { $ } from '@xec-sh/core';
// Executes using your system's default shell
const result = await $`echo "Hello, World!"`;
console.log(result.stdout); // "Hello, World!"
Custom Configuration
Configure the local adapter for specific requirements:
import { createExecutionEngine } from '@xec-sh/core';
const engine = createExecutionEngine({
adapters: {
local: {
// Prefer Bun runtime if available
preferBun: true,
// Force specific implementation
forceImplementation: 'node', // or 'bun'
// Set user/group IDs (Unix only)
uid: 1000,
gid: 1000,
// Custom kill signal
killSignal: 'SIGTERM',
// Default timeout
defaultTimeout: 30000,
// Output encoding
encoding: 'utf8',
// Maximum buffer size (10MB)
maxBuffer: 10 * 1024 * 1024
}
}
});
const result = await engine.execute({ adapter: 'local' }, 'ls -la');
Shell Configuration
Shell Detection
The local adapter automatically detects your system shell:
// Auto-detection based on platform
const result = await $`echo $0`;
// Output: /bin/bash (Linux/Mac) or cmd.exe (Windows)
Explicit Shell Selection
Specify which shell to use:
// Use specific shell binary
await $.with({ shell: '/bin/bash' })`echo $BASH_VERSION`;
await $.with({ shell: '/bin/zsh' })`echo $ZSH_VERSION`;
await $.with({ shell: '/usr/bin/fish' })`echo $FISH_VERSION`;
// Use boolean for system default
await $.with({ shell: true })`echo "Using system shell"`;
// Disable shell (direct execution)
await $.with({ shell: false })`/usr/bin/node --version`;
Shell Options
Configure shell-specific behavior:
// Bash with specific options
await $.with({
shell: '/bin/bash',
env: {
BASH_ENV: '~/.bashrc',
SHELLOPTS: 'errexit:nounset'
}
})`source ~/.bash_profile && run-command`;
// PowerShell on Windows
await $.with({
shell: 'powershell.exe'
})`Get-Process | Where-Object {$_.CPU -gt 100}`;
// Command prompt on Windows
await $.with({
shell: 'cmd.exe'
})`dir /b *.txt`;
Runtime Selection
Automatic Runtime Detection
The adapter automatically detects and uses the best available runtime:
import { RuntimeDetector } from '@xec-sh/core';
if (RuntimeDetector.isBun()) {
console.log('Running with Bun - optimized performance');
} else {
console.log('Running with Node.js');
}
// Execution automatically uses detected runtime
await $`node --version || bun --version`;
Bun Optimization
When Bun is available, the adapter uses optimized APIs:
// Configure to prefer Bun
const engine = createExecutionEngine({
adapters: {
local: {
preferBun: true // Use Bun.spawn when available
}
}
});
// Force Bun implementation (fails if Bun not available)
const bunEngine = createExecutionEngine({
adapters: {
local: {
forceImplementation: 'bun'
}
}
});
Process Management
Working Directory
Set the working directory for command execution:
// Relative path (from current working directory)
await $.with({ cwd: './src' })`ls -la`;
// Absolute path
await $.with({ cwd: '/tmp' })`pwd`; // Output: /tmp
// Chain directory changes
const projectDir = '/home/user/project';
await $.with({ cwd: projectDir })`npm install`;
await $.with({ cwd: `${projectDir}/src` })`npm test`;
Environment Variables
Manage environment variables for processes:
// Add specific variables
await $.with({
env: {
NODE_ENV: 'production',
DEBUG: 'app:*'
}
})`node app.js`;
// Merge with existing environment
await $.with({
env: {
...process.env,
CUSTOM_VAR: 'value'
}
})`./script.sh`;
// Clear environment (Unix only)
await $.with({
env: {}
})`env`; // Shows empty environment
Process Signals
Handle process signals and termination:
// Custom timeout with specific signal
const proc = $.with({
timeout: 5000,
killSignal: 'SIGKILL'
})`sleep 10`;
try {
await proc;
} catch (error) {
console.log('Process killed after timeout');
}
// Manual signal handling
const longRunning = $`tail -f /var/log/system.log`;
// Kill after 10 seconds
setTimeout(() => longRunning.kill('SIGTERM'), 10000);
// Handle graceful shutdown
process.on('SIGINT', async () => {
longRunning.kill();
await longRunning.catch(() => {}); // Ignore kill error
process.exit(0);
});
Input/Output Streams
Standard Input
Provide input to processes:
// String input
await $.with({ stdin: 'Hello, World!' })`cat`;
// Buffer input
const buffer = Buffer.from('Binary data', 'utf8');
await $.with({ stdin: buffer })`wc -c`;
// Stream input
import { createReadStream } from 'fs';
const stream = createReadStream('input.txt');
await $.with({ stdin: stream })`grep "pattern"`;
// Pipe from another command
const output = await $`echo "test"`;
await $.with({ stdin: output.stdout })`tr '[:lower:]' '[:upper:]'`;
Output Handling
Control how output is captured:
// Default - capture stdout and stderr
const result = await $`ls -la`;
console.log(result.stdout);
console.log(result.stderr);
// Inherit parent's stdio
await $.with({
stdout: 'inherit',
stderr: 'inherit'
})`npm install`; // Output goes directly to console
// Ignore output
await $.with({
stdout: 'ignore',
stderr: 'ignore'
})`silent-command`;
// Pipe to custom streams
import { createWriteStream } from 'fs';
const logFile = createWriteStream('output.log');
await $.with({
stdout: logFile,
stderr: logFile
})`verbose-command`;
Error Handling
Exit Code Handling
Configure how non-zero exit codes are handled:
// Default - throw on non-zero exit
try {
await $`exit 1`;
} catch (error) {
console.log('Exit code:', error.exitCode); // 1
console.log('Command:', error.command); // "exit 1"
}
// Don't throw on non-zero exit
const result = await $.with({ throwOnNonZeroExit: false })`exit 42`;
console.log(result.exitCode); // 42
console.log(result.failed); // true
// Check specific exit codes
const { exitCode } = await $.with({ throwOnNonZeroExit: false })`grep "pattern" file.txt`;
if (exitCode === 0) {
console.log('Pattern found');
} else if (exitCode === 1) {
console.log('Pattern not found');
} else {
console.log('Error occurred');
}
Timeout Handling
Set execution timeouts:
// Timeout with error
try {
await $.with({ timeout: 1000 })`sleep 5`;
} catch (error) {
if (error.name === 'TimeoutError') {
console.log('Command timed out after', error.timeout, 'ms');
}
}
// Timeout with custom signal
await $.with({
timeout: 5000,
killSignal: 'SIGKILL' // Force kill on timeout
})`potentially-hanging-command`;
// No timeout (default)
await $.with({ timeout: 0 })`long-running-process`;
Error Context
Access detailed error information:
try {
await $.with({ cwd: '/nonexistent' })`ls`;
} catch (error) {
console.log('Error code:', error.code); // 'ENOENT'
console.log('Exit code:', error.exitCode); // null (spawn failed)
console.log('Signal:', error.signal); // null
console.log('Command:', error.command); // 'ls'
console.log('Working dir:', error.cwd); // '/nonexistent'
console.log('Stack trace:', error.stack);
}
Performance Optimization
Buffer Management
Control memory usage for large outputs:
// Increase buffer for large outputs
const result = await $.with({
maxBuffer: 100 * 1024 * 1024 // 100MB
})`cat large-file.txt`;
// Stream processing for unlimited output
const proc = $`find / -type f`;
proc.stdout.pipe(process.stdout);
await proc;
Parallel Execution
Run multiple commands efficiently:
// Parallel execution
const [result1, result2, result3] = await Promise.all([
$`command1`,
$`command2`,
$`command3`
]);
// Sequential with shared state
const tempDir = await $`mktemp -d`;
await $.with({ cwd: tempDir.stdout.trim() })`touch file1.txt`;
await $.with({ cwd: tempDir.stdout.trim() })`touch file2.txt`;
Process Reuse
Optimize repeated executions:
// Create reusable configuration
const nodeExec = (script) => $.with({
shell: false,
timeout: 10000
})`node -e ${script}`;
// Reuse configuration
await nodeExec('console.log("Test 1")');
await nodeExec('console.log("Test 2")');
await nodeExec('console.log("Test 3")');
Platform-Specific Features
Unix/Linux/macOS
Unix-specific features and configurations:
// Set user and group IDs
await $.with({
uid: 1000,
gid: 1000
})`whoami`;
// Use shell features
await $.with({ shell: '/bin/bash' })`
set -euo pipefail
source ~/.bashrc
alias ll='ls -la'
ll /tmp
`;
// Signal handling
const proc = $`sleep 100`;
proc.kill('SIGUSR1'); // Send custom signal